Валленланд Вики vlwiki https://vl.skywiki.org/wiki/%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0 MediaWiki 1.43.1 first-letter Медиа Служебная Обсуждение Участник Обсуждение участника Валленланд Вики Валленланд Вики talk Файл Обсуждение файла MediaWiki Обсуждение MediaWiki Шаблон Обсуждение шаблона Справка Обсуждение справки Категория Обсуждение категории GeoJson GeoJson talk Campaign Campaign talk Модуль Обсуждение модуля Шаблон:Флагификация/Великобритания 10 71 139 2010-05-18T20:27:18Z wikipedia:ru>Rubinbot II 0 Защищена «[[Шаблон:Флагификация/Великобритания]]»: критический шаблон ([edit=sysop] (бессрочно) [move=sysop] (бессрочно)) wikitext text/x-wiki {{ {{{1<noinclude>|флагификация/флаг</noinclude>}}} | alias = Великобритания | flag alias = Flag of the United Kingdom.svg | flag alias-1707 = Union flag 1606 (Kings Colors).svg | flag alias-1658 = Flag of the Commonwealth (1658-1660).svg | flag alias-1651 = Flag of The Commonwealth.svg | flag alias-1649 = Flag of the Commonwealth (1649-1651).svg | flag alias-1606 = Union flag 1606 (Kings Colors).svg | flag alias-ВМС = Naval Ensign of the United Kingdom.svg | flag alias-торговый = Civil Ensign of the United Kingdom.svg | flag alias-ВВС = Ensign of the Royal Air Force.svg | flag alias-дипломатический = Government Ensign of the United Kingdom.svg | flag alias-армия = Flag of the British Army.svg | variant = {{{variant|}}} <noinclude> | var1 = 1707 | var2 = 1658 | var3 = 1651 | var4 = 1649 | var5 = 1606 | var6 = ВМС | var7 = торговый | var8 = ВВС | var9 = дипломатический | var10 = армия </noinclude> | размер = {{{размер|}}} }} 4bf44640a433c2a79fdf1d0e148897cad36f0f4d Шаблон:Str len 10 75 147 2013-03-14T14:34:59Z wikipedia:ru>DR 0 wikitext text/x-wiki {{{{{|safesubst:}}}#invoke:String|len|s={{{1|}}}}}<noinclude> {{doc}} <!-- Add categories and interwikis to the /doc subpage, not here! --> </noinclude> 95f10258d5214440d2706952656564f216c2e4cc Шаблон:Str rep 10 28 53 2015-02-28T09:38:11Z wikipedia:ru>Rubinbot II 0 Защищена Шаблон:Str rep: Top used templates to be protected ([Редактирование=только администраторы] (бессрочно) [Переименование=только администраторы] (бессро wikitext text/x-wiki <includeonly>{{{{{|safesubst:}}}#invoke:String|replace|source={{{1}}}|{{{2}}}|{{{3}}}|{{{4|1}}}}}</includeonly><noinclude>{{doc}}</noinclude> c75032f150c372324c69a6f62ff4ab1492ad4cfa Модуль:Namespace detect/data 828 22 41 2015-06-27T21:11:34Z wikipedia:ru>Draa kul 0 Защищена Модуль:Namespace detect/data: критический шаблон ([Редактирование=только администраторы] (бессрочно) [Переименование=только администрато… Scribunto text/plain -------------------------------------------------------------------------------- -- Namespace detect data -- -- This module holds data for [[Module:Namespace detect]] to be loaded per -- -- page, rather than per #invoke, for performance reasons. -- -------------------------------------------------------------------------------- local cfg = require('Module:Namespace detect/config') local function addKey(t, key, defaultKey) if key ~= defaultKey then t[#t + 1] = key end end -- Get a table of parameters to query for each default parameter name. -- This allows wikis to customise parameter names in the cfg table while -- ensuring that default parameter names will always work. The cfg table -- values can be added as a string, or as an array of strings. local defaultKeys = { 'main', 'talk', 'other', 'subjectns', 'demospace', 'demopage' } local argKeys = {} for i, defaultKey in ipairs(defaultKeys) do argKeys[defaultKey] = {defaultKey} end for defaultKey, t in pairs(argKeys) do local cfgValue = cfg[defaultKey] local cfgValueType = type(cfgValue) if cfgValueType == 'string' then addKey(t, cfgValue, defaultKey) elseif cfgValueType == 'table' then for i, key in ipairs(cfgValue) do addKey(t, key, defaultKey) end end cfg[defaultKey] = nil -- Free the cfg value as we don't need it any more. end local function getParamMappings() --[[ -- Returns a table of how parameter names map to namespace names. The keys -- are the actual namespace names, in lower case, and the values are the -- possible parameter names for that namespace, also in lower case. The -- table entries are structured like this: -- { -- [''] = {'main'}, -- ['wikipedia'] = {'wikipedia', 'project', 'wp'}, -- ... -- } --]] local mappings = {} local mainNsName = mw.site.subjectNamespaces[0].name mainNsName = mw.ustring.lower(mainNsName) mappings[mainNsName] = mw.clone(argKeys.main) mappings['talk'] = mw.clone(argKeys.talk) for nsid, ns in pairs(mw.site.subjectNamespaces) do if nsid ~= 0 then -- Exclude main namespace. local nsname = mw.ustring.lower(ns.name) local canonicalName = mw.ustring.lower(ns.canonicalName) mappings[nsname] = {nsname} if canonicalName ~= nsname then table.insert(mappings[nsname], canonicalName) end for _, alias in ipairs(ns.aliases) do table.insert(mappings[nsname], mw.ustring.lower(alias)) end end end return mappings end return { argKeys = argKeys, cfg = cfg, mappings = getParamMappings() } d224f42a258bc308ef3ad8cc8686cd7a4f47d005 Модуль:Namespace detect/config 828 23 43 2015-06-27T21:11:46Z wikipedia:ru>Draa kul 0 Защищена Модуль:Namespace detect/config: критический шаблон ([Редактирование=только администраторы] (бессрочно) [Переименование=только администрат… Scribunto text/plain -------------------------------------------------------------------------------- -- Namespace detect configuration data -- -- -- -- This module stores configuration data for Module:Namespace detect. Here -- -- you can localise the module to your wiki's language. -- -- -- -- To activate a configuration item, you need to uncomment it. This means -- -- that you need to remove the text "-- " at the start of the line. -- -------------------------------------------------------------------------------- local cfg = {} -- Don't edit this line. -------------------------------------------------------------------------------- -- Parameter names -- -- These configuration items specify custom parameter names. Values added -- -- here will work in addition to the default English parameter names. -- -- To add one extra name, you can use this format: -- -- -- -- cfg.foo = 'parameter name' -- -- -- -- To add multiple names, you can use this format: -- -- -- -- cfg.foo = {'parameter name 1', 'parameter name 2', 'parameter name 3'} -- -------------------------------------------------------------------------------- ---- This parameter displays content for the main namespace: -- cfg.main = 'main' ---- This parameter displays in talk namespaces: -- cfg.talk = 'talk' ---- This parameter displays content for "other" namespaces (namespaces for which ---- parameters have not been specified): -- cfg.other = 'other' ---- This parameter makes talk pages behave as though they are the corresponding ---- subject namespace. Note that this parameter is used with [[Module:Yesno]]. ---- Edit that module to change the default values of "yes", "no", etc. -- cfg.subjectns = 'subjectns' ---- This parameter sets a demonstration namespace: -- cfg.demospace = 'demospace' ---- This parameter sets a specific page to compare: cfg.demopage = 'page' -------------------------------------------------------------------------------- -- Table configuration -- -- These configuration items allow customisation of the "table" function, -- -- used to generate a table of possible parameters in the module -- -- documentation. -- -------------------------------------------------------------------------------- ---- The header for the namespace column in the wikitable containing the list of ---- possible subject-space parameters. -- cfg.wikitableNamespaceHeader = 'Namespace' ---- The header for the wikitable containing the list of possible subject-space ---- parameters. -- cfg.wikitableAliasesHeader = 'Aliases' -------------------------------------------------------------------------------- -- End of configuration data -- -------------------------------------------------------------------------------- return cfg -- Don't edit this line. 0e4ff08d13c4b664d66b32c232deb129b77c1a56 Модуль:Color contrast/colors 828 65 127 2016-06-19T09:05:16Z wikipedia:ru>Dima st bk 0 Защищена Модуль:Color contrast/colors: критический шаблон ([Редактирование=только администраторы] (бессрочно) [Переименование=только администрато… Scribunto text/plain return { aliceblue = 0.92880068253475, antiquewhite = 0.84646951707754, aqua = 0.7874, aquamarine = 0.8078549208338, azure = 0.97265264954166, beige = 0.8988459998705, bisque = 0.80732327372979, black = 0, blanchedalmond = 0.85084439608156, blue = 0.0722, blueviolet = 0.12622014321946, brown = 0.098224287876511, burlywood = 0.51559844533893, cadetblue = 0.29424681085422, chartreuse = 0.76032025902623, chocolate = 0.23898526114557, coral = 0.37017930872924, cornflowerblue = 0.30318641994179, cornsilk = 0.93562110372965, crimson = 0.16042199953026, cyan = 0.7874, darkblue = 0.018640801980939, darkcyan = 0.20329317839046, darkgoldenrod = 0.27264703559993, darkgray = 0.39675523072563, darkgreen = 0.091143429047575, darkgrey = 0.39675523072563, darkkhaki = 0.45747326349994, darkmagenta = 0.07353047651207, darkolivegreen = 0.12651920884889, darkorange = 0.40016167026524, darkorchid = 0.13413142174857, darkred = 0.054889674531132, darksalmon = 0.40541471563381, darkseagreen = 0.43789249325969, darkslateblue = 0.065792846227988, darkslategray = 0.067608151928044, darkslategrey = 0.067608151928044, darkturquoise = 0.4874606277449, darkviolet = 0.10999048339343, deeppink = 0.23866895828276, deepskyblue = 0.44481603395575, dimgray = 0.14126329114027, dimgrey = 0.14126329114027, dodgerblue = 0.27442536991456, firebrick = 0.10724525535015, floralwhite = 0.95922484825004, forestgreen = 0.18920812076002, fuchsia = 0.2848, gainsboro = 0.71569350050648, ghostwhite = 0.94311261886323, gold = 0.69860877428159, goldenrod = 0.41919977809569, gray = 0.2158605001139, green = 0.15438342968146, greenyellow = 0.80609472611453, grey = 0.2158605001139, honeydew = 0.96336535554782, hotpink = 0.34658438169715, indianred = 0.21406134963884, indigo = 0.03107561486337, ivory = 0.99071270600615, khaki = 0.77012343394121, lavender = 0.80318750514521, lavenderblush = 0.90172748631046, lawngreen = 0.73905893124963, lemonchiffon = 0.94038992245622, lightblue = 0.63709141280807, lightcoral = 0.35522120733135, lightcyan = 0.94587293494829, lightgoldenrodyellow = 0.93348351018297, lightgray = 0.65140563741982, lightgreen = 0.69091979956865, lightgrey = 0.65140563741982, lightpink = 0.58566152734898, lightsalmon = 0.4780675225206, lightseagreen = 0.35050145117042, lightskyblue = 0.56195637618331, lightslategray = 0.23830165007287, lightslategrey = 0.23830165007287, lightsteelblue = 0.53983888284666, lightyellow = 0.98161818392882, lime = 0.7152, limegreen = 0.44571042246098, linen = 0.88357340984379, magenta = 0.2848, maroon = 0.045891942324215, mediumaquamarine = 0.49389703310801, mediumblue = 0.044077780212328, mediumorchid = 0.21639251153773, mediumpurple = 0.22905858091648, mediumseagreen = 0.34393112338131, mediumslateblue = 0.20284629471622, mediumspringgreen = 0.70704308194184, mediumturquoise = 0.5133827926448, mediumvioletred = 0.14371899849357, midnightblue = 0.02071786635086, mintcream = 0.97834604947588, mistyrose = 0.82183047859185, moccasin = 0.80083000991567, navajowhite = 0.76519682342785, navy = 0.015585128108224, oldlace = 0.91900633405549, olive = 0.20027537200568, olivedrab = 0.22593150951929, orange = 0.4817026703631, orangered = 0.25516243753416, orchid = 0.31348806761439, palegoldenrod = 0.78792647887614, palegreen = 0.77936759006353, paleturquoise = 0.76436077921714, palevioletred = 0.28754994117889, papayawhip = 0.87797100199835, peachpuff = 0.74905589878251, peru = 0.30113074877936, pink = 0.63271070702466, plum = 0.45734221587969, powderblue = 0.68254586500605, purple = 0.061477070432439, rebeccapurple = 0.07492341159447, red = 0.2126, rosybrown = 0.32319457649407, royalblue = 0.16663210743188, saddlebrown = 0.097922285020521, salmon = 0.36977241527596, sandybrown = 0.46628543696283, seagreen = 0.19734199706275, seashell = 0.92737862206922, sienna = 0.13697631337098, silver = 0.52711512570581, skyblue = 0.55291668518184, slateblue = 0.14784278062136, slategray = 0.20896704076536, slategrey = 0.20896704076536, snow = 0.96533341834849, springgreen = 0.73052306068529, steelblue = 0.20562642207625, tan = 0.48237604163921, teal = 0.16996855778968, thistle = 0.56818401093733, tomato = 0.30638612719415, turquoise = 0.5895536427578, violet = 0.40315452986676, wheat = 0.74909702820482, white = 1, whitesmoke = 0.91309865179342, yellow = 0.9278, yellowgreen = 0.50762957208707, } 6ae47fdb24de4eed5ec26d203faf5341a388987b Шаблон:Wikidata/p570 10 47 91 2016-07-12T17:40:22Z wikipedia:ru>Putnik 0 скрытие значения из Викиданных при помощи «-» wikitext text/x-wiki {{#switch:{{{1|}}}|-=|={{#invoke:Wikidata|formatStatements|property=p570|claim-module=Wikidata/date|claim-function=formatDateOfDeathClaim|nocat={{{nocat|}}}{{NAMESPACE}}}}|{{#invoke:Infocards|dateOfDeath|{{{2|}}}|{{{1|}}}|nocat={{{nocat|}}}{{NAMESPACE}}}}}}<noinclude>{{doc}}</noinclude> a51af6d007d156cfeacb13a0a4a7471da7d4ed22 Шаблон:Str find 10 52 101 2016-11-07T15:00:14Z wikipedia:ru>Jack who built the house 0 последуем написанному в комментарии и перенесём категории на подстраницу wikitext text/x-wiki {{ {{{|safesubst:}}}#invoke:String|str_find|source={{{1|}}}|{{{2|}}}}}<noinclude> {{doc}} <!-- Add categories and interwikis to the /doc subpage, not here! --> </noinclude> 18d1469d30d27a82ee15fd2fb1ca12a34b5f5e87 Шаблон:Nobr 10 48 93 2016-12-02T13:15:38Z wikipedia:ru>Jack who built the house 0 используем класс nowrap wikitext text/x-wiki <includeonly><span class="nowrap">{{{1}}}</span></includeonly><noinclude> {{doc}} <!-- Пожалуйста, добавляйте категории и интервики на страницу документации! --> </noinclude> 989c6f164ed3a8543e916c8f1746ba1ab94fb068 Шаблон:Delink 10 38 73 2017-08-01T19:23:44Z wikipedia:ru>Q-bit array 0 Защитил «[[Шаблон:Delink]]»: критический шаблон ([Редактирование=только администраторы] (бессрочно) [Переименование=только администраторы] (б… wikitext text/x-wiki {{<includeonly>safesubst:</includeonly>#invoke:delink|delink}}<noinclude> {{doc}} </noinclude> dbac86e53b946e60d5b6236381e8c31858e79ee5 Шаблон:Карточка/имя 10 44 85 2017-08-01T19:26:40Z wikipedia:ru>Q-bit array 0 Защитил «[[Шаблон:Карточка/имя]]»: критический шаблон ([Редактирование=только администраторы] (бессрочно) [Переименование=только админист… wikitext text/x-wiki {{#if:{{{1|}}}|{{{1}}}|{{сначала имя|{{PAGENAME}}}}}}<noinclude> {{doc}} </noinclude> c2c97d1196f5c50a2ec1aa866cd4004526a32383 Модуль:Category handler/config 828 19 35 2017-08-01T19:26:42Z wikipedia:ru>Q-bit array 0 Защитил «[[Модуль:Category handler/config]]»: критический шаблон ([Редактирование=только администраторы] (бессрочно) [Переименование=только админист… Scribunto text/plain -------------------------------------------------------------------------------- -- [[Module:Category handler]] configuration data -- -- Language-specific parameter names and values can be set here. -- -- For blacklist config, see [[Module:Category handler/blacklist]]. -- -------------------------------------------------------------------------------- local cfg = {} -- Don't edit this line. -------------------------------------------------------------------------------- -- Start configuration data -- -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- -- Parameter names -- -- These configuration items specify custom parameter names. -- -- To add one extra name, you can use this format: -- -- -- -- foo = 'parameter name', -- -- -- -- To add multiple names, you can use this format: -- -- -- -- foo = {'parameter name 1', 'parameter name 2', 'parameter name 3'}, -- -------------------------------------------------------------------------------- cfg.parameters = { -- The nocat and categories parameter suppress -- categorisation. They are used with Module:Yesno, and work as follows: -- -- cfg.nocat: -- Result of yesno() Effect -- true Categorisation is suppressed -- false Categorisation is allowed, and -- the blacklist check is skipped -- nil Categorisation is allowed -- -- cfg.categories: -- Result of yesno() Effect -- true Categorisation is allowed, and -- the blacklist check is skipped -- false Categorisation is suppressed -- nil Categorisation is allowed nocat = 'nocat', categories = 'categories', -- The parameter name for the legacy "category2" parameter. This skips the -- blacklist if set to the cfg.category2Yes value, and suppresses -- categorisation if present but equal to anything other than -- cfg.category2Yes or cfg.category2Negative. category2 = 'category2', -- cfg.subpage is the parameter name to specify how to behave on subpages. subpage = 'subpage', -- The parameter for data to return in all namespaces. all = 'all', -- The parameter name for data to return if no data is specified for the -- namespace that is detected. other = 'other', -- The parameter name used to specify a page other than the current page; -- used for testing and demonstration. demopage = 'page', } -------------------------------------------------------------------------------- -- Parameter values -- -- These are set values that can be used with certain parameters. Only one -- -- value can be specified, like this: -- -- -- -- cfg.foo = 'value name' -- -- -------------------------------------------------------------------------------- -- The following settings are used with the cfg.category2 parameter. Setting -- cfg.category2 to cfg.category2Yes skips the blacklist, and if cfg.category2 -- is present but equal to anything other than cfg.category2Yes or -- cfg.category2Negative then it supresses cateogrisation. cfg.category2Yes = 'yes' cfg.category2Negative = '¬' -- The following settings are used with the cfg.subpage parameter. -- cfg.subpageNo is the value to specify to not categorise on subpages; -- cfg.subpageOnly is the value to specify to only categorise on subpages. cfg.subpageNo = 'no' cfg.subpageOnly = 'only' -------------------------------------------------------------------------------- -- Default namespaces -- -- This is a table of namespaces to categorise by default. The keys are the -- -- namespace numbers. -- -------------------------------------------------------------------------------- cfg.defaultNamespaces = { [ 0] = true, -- main [ 6] = true, -- file [ 12] = true, -- help [ 14] = true, -- category [100] = true, -- portal [108] = true, -- book } -------------------------------------------------------------------------------- -- Wrappers -- -- This is a wrapper template or a list of wrapper templates to be passed to -- -- [[Module:Arguments]]. -- -------------------------------------------------------------------------------- cfg.wrappers = 'Template:Category handler' -------------------------------------------------------------------------------- -- End configuration data -- -------------------------------------------------------------------------------- return cfg -- Don't edit this line. 373cd107b13a5b00e6a1b7e66a749f12502c849d Модуль:Category handler/blacklist 828 21 39 2017-08-01T19:26:43Z wikipedia:ru>Q-bit array 0 Защитил «[[Модуль:Category handler/blacklist]]»: критический шаблон ([Редактирование=только администраторы] (бессрочно) [Переименование=только админис… Scribunto text/plain -- This module contains the blacklist used by [[Module:Category handler]]. -- Pages that match Lua patterns in this list will not be categorised unless -- categorisation is explicitly requested. return { '^Main Page$', -- don't categorise the main page. -- Don't categorise the following pages or their subpages. -- "%f[/\0]" matches if the next character is "/" or the end of the string. '^Wikipedia:Cascade%-protected items%f[/\0]', '^User:UBX%f[/\0]', -- The userbox "template" space. '^User talk:UBX%f[/\0]', -- Don't categorise subpages of these pages, but allow -- categorisation of the base page. '^Wikipedia:Template messages/.*$', '/[aA]rchive' -- Don't categorise archives. } c84948ad9808d5d323408d5d10d5652f748a0550 Модуль:Category handler 828 15 27 2017-08-01T19:26:45Z wikipedia:ru>Q-bit array 0 Защитил «[[Модуль:Category handler]]»: критический шаблон ([Редактирование=только администраторы] (бессрочно) [Переименование=только администрато… Scribunto text/plain -------------------------------------------------------------------------------- -- -- -- CATEGORY HANDLER -- -- -- -- This module implements the {{category handler}} template in Lua, -- -- with a few improvements: all namespaces and all namespace aliases -- -- are supported, and namespace names are detected automatically for -- -- the local wiki. This module requires [[Module:Namespace detect]] -- -- and [[Module:Yesno]] to be available on the local wiki. It can be -- -- configured for different wikis by altering the values in -- -- [[Module:Category handler/config]], and pages can be blacklisted -- -- from categorisation by using [[Module:Category handler/blacklist]]. -- -- -- -------------------------------------------------------------------------------- -- Load required modules local yesno = require('Module:Yesno') -- Lazily load things we don't always need local mShared, mappings local p = {} -------------------------------------------------------------------------------- -- Helper functions -------------------------------------------------------------------------------- local function trimWhitespace(s, removeBlanks) if type(s) ~= 'string' then return s end s = s:match('^%s*(.-)%s*$') if removeBlanks then if s ~= '' then return s else return nil end else return s end end -------------------------------------------------------------------------------- -- CategoryHandler class -------------------------------------------------------------------------------- local CategoryHandler = {} CategoryHandler.__index = CategoryHandler function CategoryHandler.new(data, args) local obj = setmetatable({ _data = data, _args = args }, CategoryHandler) -- Set the title object do local pagename = obj:parameter('demopage') local success, titleObj if pagename then success, titleObj = pcall(mw.title.new, pagename) end if success and titleObj then obj.title = titleObj if titleObj == mw.title.getCurrentTitle() then obj._usesCurrentTitle = true end else obj.title = mw.title.getCurrentTitle() obj._usesCurrentTitle = true end end -- Set suppression parameter values for _, key in ipairs{'nocat', 'categories'} do local value = obj:parameter(key) value = trimWhitespace(value, true) obj['_' .. key] = yesno(value) end do local subpage = obj:parameter('subpage') local category2 = obj:parameter('category2') if type(subpage) == 'string' then subpage = mw.ustring.lower(subpage) end if type(category2) == 'string' then subpage = mw.ustring.lower(category2) end obj._subpage = trimWhitespace(subpage, true) obj._category2 = trimWhitespace(category2) -- don't remove blank values end return obj end function CategoryHandler:parameter(key) local parameterNames = self._data.parameters[key] local pntype = type(parameterNames) if pntype == 'string' or pntype == 'number' then return self._args[parameterNames] elseif pntype == 'table' then for _, name in ipairs(parameterNames) do local value = self._args[name] if value ~= nil then return value end end return nil else error(string.format( 'invalid config key "%s"', tostring(key) ), 2) end end function CategoryHandler:isSuppressedByArguments() return -- See if a category suppression argument has been set. self._nocat == true or self._categories == false or ( self._category2 and self._category2 ~= self._data.category2Yes and self._category2 ~= self._data.category2Negative ) -- Check whether we are on a subpage, and see if categories are -- suppressed based on our subpage status. or self._subpage == self._data.subpageNo and self.title.isSubpage or self._subpage == self._data.subpageOnly and not self.title.isSubpage end function CategoryHandler:shouldSkipBlacklistCheck() -- Check whether the category suppression arguments indicate we -- should skip the blacklist check. return self._nocat == false or self._categories == true or self._category2 == self._data.category2Yes end function CategoryHandler:matchesBlacklist() if self._usesCurrentTitle then return self._data.currentTitleMatchesBlacklist else mShared = mShared or require('Module:Category handler/shared') return mShared.matchesBlacklist( self.title.prefixedText, mw.loadData('Module:Category handler/blacklist') ) end end function CategoryHandler:isSuppressed() -- Find if categories are suppressed by either the arguments or by -- matching the blacklist. return self:isSuppressedByArguments() or not self:shouldSkipBlacklistCheck() and self:matchesBlacklist() end function CategoryHandler:getNamespaceParameters() if self._usesCurrentTitle then return self._data.currentTitleNamespaceParameters else if not mappings then mShared = mShared or require('Module:Category handler/shared') mappings = mShared.getParamMappings(true) -- gets mappings with mw.loadData end return mShared.getNamespaceParameters( self.title, mappings ) end end function CategoryHandler:namespaceParametersExist() -- Find whether any namespace parameters have been specified. -- We use the order "all" --> namespace params --> "other" as this is what -- the old template did. if self:parameter('all') then return true end if not mappings then mShared = mShared or require('Module:Category handler/shared') mappings = mShared.getParamMappings(true) -- gets mappings with mw.loadData end for ns, params in pairs(mappings) do for i, param in ipairs(params) do if self._args[param] then return true end end end if self:parameter('other') then return true end return false end function CategoryHandler:getCategories() local params = self:getNamespaceParameters() local nsCategory for i, param in ipairs(params) do local value = self._args[param] if value ~= nil then nsCategory = value break end end if nsCategory ~= nil or self:namespaceParametersExist() then -- Namespace parameters exist - advanced usage. if nsCategory == nil then nsCategory = self:parameter('other') end local ret = {self:parameter('all')} local numParam = tonumber(nsCategory) if numParam and numParam >= 1 and math.floor(numParam) == numParam then -- nsCategory is an integer ret[#ret + 1] = self._args[numParam] else ret[#ret + 1] = nsCategory end if #ret < 1 then return nil else return table.concat(ret) end elseif self._data.defaultNamespaces[self.title.namespace] then -- Namespace parameters don't exist, simple usage. return self._args[1] end return nil end -------------------------------------------------------------------------------- -- Exports -------------------------------------------------------------------------------- local p = {} function p._exportClasses() -- Used for testing purposes. return { CategoryHandler = CategoryHandler } end function p._main(args, data) data = data or mw.loadData('Module:Category handler/data') local handler = CategoryHandler.new(data, args) if handler:isSuppressed() then return nil end return handler:getCategories() end function p.main(frame, data) data = data or mw.loadData('Module:Category handler/data') local args = require('Module:Arguments').getArgs(frame, { wrappers = data.wrappers, valueFunc = function (k, v) v = trimWhitespace(v) if type(k) == 'number' then if v ~= '' then return v else return nil end else return v end end }) return p._main(args, data) end return p b74dd63857b24904ac452429b11213f18647471f Модуль:Category handler/shared 828 20 37 2017-08-01T19:26:47Z wikipedia:ru>Q-bit array 0 Защитил «[[Модуль:Category handler/shared]]»: критический шаблон ([Редактирование=только администраторы] (бессрочно) [Переименование=только админист… Scribunto text/plain -- This module contains shared functions used by [[Module:Category handler]] -- and its submodules. local p = {} function p.matchesBlacklist(page, blacklist) for i, pattern in ipairs(blacklist) do local match = mw.ustring.match(page, pattern) if match then return true end end return false end function p.getParamMappings(useLoadData) local dataPage = 'Module:Namespace detect/data' if useLoadData then return mw.loadData(dataPage).mappings else return require(dataPage).mappings end end function p.getNamespaceParameters(titleObj, mappings) -- We don't use title.nsText for the namespace name because it adds -- underscores. local mappingsKey if titleObj.isTalkPage then mappingsKey = 'talk' else mappingsKey = mw.site.namespaces[titleObj.namespace].name end mappingsKey = mw.ustring.lower(mappingsKey) return mappings[mappingsKey] or {} end return p d2d5de1a031e6ce97c242cbfa8afe7a92cb9eca5 Модуль:Category handler/data 828 18 33 2017-08-01T19:26:49Z wikipedia:ru>Q-bit array 0 Защитил «[[Модуль:Category handler/data]]»: критический шаблон ([Редактирование=только администраторы] (бессрочно) [Переименование=только администр… Scribunto text/plain -- This module assembles data to be passed to [[Module:Category handler]] using -- mw.loadData. This includes the configuration data and whether the current -- page matches the title blacklist. local data = require('Module:Category handler/config') local mShared = require('Module:Category handler/shared') local blacklist = require('Module:Category handler/blacklist') local title = mw.title.getCurrentTitle() data.currentTitleMatchesBlacklist = mShared.matchesBlacklist( title.prefixedText, blacklist ) data.currentTitleNamespaceParameters = mShared.getNamespaceParameters( title, mShared.getParamMappings() ) return data abbc68048ff698e88dda06b64ecf384bbf583120 Шаблон:Yesno 10 25 47 2017-08-01T19:30:50Z wikipedia:ru>Q-bit array 0 Защитил «[[Шаблон:Yesno]]»: критический шаблон ([Редактирование=только администраторы] (бессрочно) [Переименование=только администраторы] (бе… wikitext text/x-wiki {{<includeonly>safesubst:</includeonly>#switch: {{<includeonly>safesubst:</includeonly>lc: {{{1|¬}}} }} |no |n |нет |false |0 = {{{no|<!-- null -->}}} | = {{{blank|{{{no|<!-- null -->}}}}}} |¬ = {{{¬|}}} |yes |y |да |true |1 = {{{yes|yes}}} |#default = {{{def|{{{yes|yes}}}}}} }}<noinclude> {{Documentation}} </noinclude> 4e236854c477d07a225c2ab6c016c389b133e8d3 Модуль:Wikidata:Dictionary/P424 828 81 159 2017-08-01T19:32:01Z wikipedia:ru>Q-bit array 0 Защитил «[[Модуль:Wikidata:Dictionary/P424]]»: критический шаблон ([Редактирование=только администраторы] (бессрочно) [Переименование=только админист… Scribunto text/plain return { Q143={'eo'}, Q150={'fr'}, Q188={'de'}, Q256={'tr'}, Q294={'is'}, Q328={'en'}, Q397={'la'}, Q652={'it'}, Q809={'pl'}, Q1321={'es'}, Q1412={'fi'}, Q1568={'hi'}, Q1571={'mr'}, Q1617={'ur'}, Q1860={'en'}, Q4627={'ay'}, Q5111={'ab'}, Q5137={'gu'}, Q5146={'pt'}, Q5218={'qu'}, Q5287={'ja'}, Q5885={'ta'}, Q6654={'hr'}, Q7026={'ca'}, Q7411={'nl'}, Q7737={'ru'}, Q7838={'sw'}, Q7850={'zh'}, Q7913={'ro'}, Q7918={'bg'}, Q7930={'mg'}, Q7979={'en-gb'}, Q8097={'te'}, Q8108={'ka'}, Q8447={'fr'}, Q8449={'es'}, Q8641={'yi'}, Q8748={'sq'}, Q8752={'eu'}, Q8765={'an'}, Q8785={'hy'}, Q8798={'uk'}, Q9027={'sv'}, Q9035={'da'}, Q9043={'no'}, Q9051={'lb'}, Q9056={'cs'}, Q9058={'sk'}, Q9063={'sl'}, Q9067={'hu'}, Q9072={'et'}, Q9078={'lv'}, Q9083={'lt'}, Q9091={'be'}, Q9129={'mis'}, Q9142={'ga'}, Q9166={'mt'}, Q9168={'fa'}, Q9176={'ko'}, Q9186={'zh-yue','yue'}, Q9199={'vi'}, Q9205={'km'}, Q9211={'lo'}, Q9217={'th'}, Q9228={'my'}, Q9237={'ms'}, Q9240={'id'}, Q9246={'mn'}, Q9252={'kk'}, Q9255={'ky'}, Q9260={'tg'}, Q9264={'uz'}, Q9267={'tk'}, Q9288={'he'}, Q9292={'az'}, Q9296={'mk'}, Q9299={'sr'}, Q9301={'sh'}, Q9303={'bs'}, Q9307={'gl'}, Q9309={'cy'}, Q9314={'gd'}, Q9610={'bn'}, Q10000={'nl'}, Q10134={'tlh'}, Q10179={'zu'}, Q10199={'diq'}, Q11059={'sa'}, Q11913={'bg'}, Q11918={'el'}, Q11920={'it'}, Q11921={'pt'}, Q12107={'br'}, Q12175={'gv'}, Q12237={'la'}, Q13198={'rcf'}, Q13199={'rm'}, Q13201={'rmy'}, Q13216={'za'}, Q13218={'xh'}, Q13238={'udm'}, Q13248={'hsb'}, Q13263={'ug'}, Q13267={'si'}, Q13275={'so'}, Q13286={'dsb'}, Q13293={'sma'}, Q13300={'nah'}, Q13307={'na'}, Q13310={'nv'}, Q13324={'min'}, Q13330={'mwl'}, Q13343={'mdf'}, Q13356={'mzn'}, Q13357={'fit'}, Q13358={'ruq'}, Q13359={'xmf'}, Q13389={'ba'}, Q13955={'ar'}, Q14185={'oc'}, Q14196={'af'}, Q14380={'sl'}, Q14549={'sco'}, Q15085={'pms'}, Q15087={'frp'}, Q17985={'ko'}, Q21117={'esu'}, Q22711={'pdc'}, Q23014={'pfl'}, Q25164={'nn'}, Q25167={'nb'}, Q25258={'fo'}, Q25285={'tt'}, Q25289={'kw'}, Q25355={'kl'}, Q25433={'nds'}, Q26245={'rue'}, Q27154={'stq'}, Q27175={'fy'}, Q27183={'ik'}, Q27683={'ace'}, Q27776={'ady'}, Q27811={'aa'}, Q28026={'ak'}, Q28224={'frr'}, Q28244={'am'}, Q28378={'anp'}, Q28602={'arc'}, Q29316={'roa-rup','rup'}, Q29401={'as'}, Q29507={'ast'}, Q29540={'bar'}, Q29561={'av'}, Q29919={'arz'}, Q29921={'iu'}, Q29952={'myv'}, Q30005={'ee'}, Q30007={'ext'}, Q30239={'zh'}, Q30319={'szl'}, Q31746={'lez'}, Q32145={'ksh'}, Q32641={'mis'}, Q32656={'dv'}, Q32704={'ve'}, Q32724={'vec'}, Q32747={'vep'}, Q32762={'fiu-vro','vro'}, Q32858={'vot'}, Q32979={'cho'}, Q33025={'bej'}, Q33081={'dz'}, Q33111={'co'}, Q33120={'bxr'}, Q33151={'bjn'}, Q33170={'ckt'}, Q33190={'bug'}, Q33202={'brh'}, Q33219={'map-bms'}, Q33239={'ceb'}, Q33243={'bm'}, Q33262={'ch'}, Q33265={'chy'}, Q33268={'bh','bho'}, Q33273={'ny'}, Q33281={'cbk-zam'}, Q33284={'bcl'}, Q33287={'gaa'}, Q33291={'fon'}, Q33295={'fj'}, Q33315={'hz'}, Q33348={'cv'}, Q33350={'ce'}, Q33357={'crh'}, Q33368={'lg'}, Q33375={'hak'}, Q33388={'chr'}, Q33390={'cr'}, Q33441={'fur'}, Q33454={'ff'}, Q33457={'gag'}, Q33475={'gan'}, Q33491={'ht'}, Q33509={'inh'}, Q33522={'kbd'}, Q33541={'kaa'}, Q33549={'jv'}, Q33552={'ks'}, Q33569={'haw'}, Q33573={'rw'}, Q33578={'ig'}, Q33583={'rn'}, Q33587={'ki'}, Q33617={'ho'}, Q33634={'xal'}, Q33657={'glk'}, Q33661={'mfe'}, Q33673={'kn'}, Q33690={'csb'}, Q33698={'liv'}, Q33702={'kg'}, Q33714={'krc'}, Q33720={'krj'}, Q33730={'arn'}, Q33754={'lmo'}, Q33786={'sid'}, Q33810={'or'}, Q33823={'ne'}, Q33845={'nap'}, Q33850={'nrm'}, Q33856={'pap'}, Q33864={'om'}, Q33879={'pag'}, Q33900={'ng'}, Q33947={'se'}, Q33954={'sg'}, Q33968={'os'}, Q33973={'scn'}, Q33976={'sc'}, Q33979={'new'}, Q33989={'srn'}, Q33997={'sd'}, Q34002={'su'}, Q34004={'sn'}, Q34011={'sm'}, Q34014={'ss'}, Q34015={'crs'}, Q34024={'pcd'}, Q34055={'tvl'}, Q34057={'tl'}, Q34094={'to'}, Q34119={'tyv'}, Q34124={'ti'}, Q34125={'tet'}, Q34128={'ty'}, Q34137={'tn'}, Q34138={'tum'}, Q34147={'vls'}, Q34159={'tpi'}, Q34208={'wbl'}, Q34219={'wa'}, Q34233={'ryu'}, Q34235={'ii'}, Q34247={'yai'}, Q34251={'tcy'}, Q34257={'wo'}, Q34271={'bo'}, Q34279={'war'}, Q34290={'wuu'}, Q34299={'sah'}, Q34311={'yo'}, Q34318={'tly'}, Q34327={'ts'}, Q34340={'st'}, Q35224={'io'}, Q35225={'peo'}, Q35452={'bi'}, Q35497={'grc'}, Q35499={'cu'}, Q35501={'prg'}, Q35722={'got'}, Q35744={'kri'}, Q35850={'ie'}, Q35853={'kab'}, Q35876={'gn'}, Q35934={'ia'}, Q35936={'ilo'}, Q35939={'jam'}, Q35963={'mis'}, Q35978={'hil'}, Q36094={'kr'}, Q36106={'lij'}, Q36109={'mai'}, Q36121={'pam'}, Q36126={'kv'}, Q36196={'lad'}, Q36206={'lbe'}, Q36212={'ltg'}, Q36217={'ln'}, Q36236={'ml'}, Q36280={'mh'}, Q36323={'pko'}, Q36350={'jbo'}, Q36368={'ku'}, Q36387={'mis'}, Q36392={'mo'}, Q36451={'mi'}, Q36455={'cdo'}, Q36495={'zh-min-nan','nan'}, Q36510={'el'}, Q36584={'olo'}, Q36699={'pis'}, Q36727={'pi'}, Q36730={'ota'}, Q36738={'nov'}, Q36748={'pnt'}, Q36811={'ckb'}, Q36850={'tw'}, Q36986={'vo'}, Q37041={'zh-classical','lzh'}, Q37059={'bpy'}, Q37178={'ine'}, Q38288={'diq'}, Q42365={'ang'}, Q44676={'en-ca'}, Q45041={'lez'}, Q46728={'hif'}, Q48183={'de'}, Q48952={'fa'}, Q53464={'hu'}, Q56240={'aeb'}, Q56318={'koi'}, Q56426={'ary'}, Q56475={'ha'}, Q56483={'lki'}, Q56499={'arq'}, Q56508={'sou'}, Q58172={'kk'}, Q58209={'ba'}, Q58215={'cv'}, Q58251={'az'}, Q58255={'tr'}, Q58635={'pa'}, Q58679={'sh'}, Q58680={'ps'}, Q58781={'rue'}, Q60786={'crh'}, Q60799={'ky'}, Q60819={'tt'}, Q60856={'ug'}, Q79633={'gag'}, Q79636={'kaa'}, Q102172={'li'}, Q131339={'als','gsw'}, Q146803={'lfn'}, Q155214={'id'}, Q169514={'sv'}, Q175482={'fi'}, Q177837={'ja'}, Q181037={'aln'}, Q181163={'da'}, Q182695={'mis'}, Q190551={'eo'}, Q191168={'cs'}, Q191769={'no'}, Q192582={'sk'}, Q199693={'ca'}, Q199698={'uk'}, Q199700={'ar'}, Q199864={'ro'}, Q199913={'he'}, Q200060={'et'}, Q200180={'vi'}, Q200183={'simple'}, Q200386={'sr','sr-ec','sr-el'}, Q202472={'lt'}, Q203488={'hr'}, Q206855={'ru'}, Q207260={'eu'}, Q208533={'sq'}, Q213434={'bat-smg','sgs'}, Q221444={'udm'}, Q225594={'sah'}, Q226150={'os'}, Q237409={'zea'}, Q242648={'eml'}, Q257829={'bqi'}, Q306626={'de-at'}, Q427715={'bn'}, Q497345={'vmf'}, Q511754={'tk'}, Q516137={'nds-nl'}, Q523014={'mus'}, Q547271={'cu'}, Q565074={'th'}, Q571001={'tpi'}, Q588620={'pam'}, Q595628={'oc'}, Q695526={'roa-tara'}, Q714826={'vo'}, Q718394={'is'}, Q722040={'hi'}, Q722243={'sw'}, Q728945={'lv'}, Q750553={'pt-br'}, Q766705={'af'}, Q824297={'mhr'}, Q837615={'ceb'}, Q841208={'gl'}, Q842341={'mk'}, Q844491={'ta'}, Q845993={'ms'}, Q846630={'cdo'}, Q846871={'br'}, Q848046={'te'}, Q848525={'cy'}, Q848974={'ka'}, Q856881={'myv'}, Q874555={'ml'}, Q875631={'ga'}, Q877583={'be'}, Q877685={'tl'}, Q880301={'frc'}, Q925661={'kv'}, Q928808={'dv'}, Q938216={'khw'}, Q940309={'szl'}, Q950058={'lb'}, Q966609={'su'}, Q1034940={'mrj'}, Q1047829={'bs'}, Q1047851={'nap'}, Q1055841={'vec'}, Q1058430={'scn'}, Q1066461={'ht'}, Q1067878={'ur'}, Q1071918={'ast'}, Q1110233={'wuu'}, Q1116066={'koi'}, Q1132977={'wa'}, Q1147071={'an'}, Q1148240={'yo'}, Q1154741={'ku'}, Q1154766={'io'}, Q1178461={'mdf'}, Q1190962={'zh-yue'}, Q1194341={'ru-sib'}, Q1211233={'als'}, Q1249553={'krc'}, Q1287192={'bpy'}, Q1291627={'new'}, Q1366643={'de-ch'}, Q1377618={'qu'}, Q1378484={'zh-classical'}, Q1389492={'pnb'}, Q1405077={'kj'}, Q1444686={'sco'}, }; c8444b1c598748668639bce6aaadca710aea0059 Модуль:URL 828 40 77 2017-09-18T16:34:08Z wikipedia:ru>Jack who built the house 0 уточнение категоризации Scribunto text/plain function startsWith( source, substring ) if mw.ustring.len( substring ) > mw.ustring.len( source ) then return false end return mw.ustring.sub( source, 1, mw.ustring.len( substring ) ) == substring end p = {} function formatUrlImpl( source, title, length ) local scheme, host, path local postfix = '' local arg1, arg2 = source, title local isTestPage = mw.title.getCurrentTitle().prefixedText == 'Модуль:URL' -- Две квадратные скобки подряд — [[вики-ссылка]] вместо [ссылки] — возвращаем вход как есть. if string.find( arg1, "[[", 1, true ) then local result = arg1 if not isTestPage then result = result .. '[[Категория:Википедия:Статьи с вики-ссылкой, переданной в Модуль:URL]]' if arg2 then -- Если есть arg2, а мы распарсить ссылку не смогли, и значит заменить title не сможем корректно, это есть ошибка. result = result .. '[[Категория:Википедия:Статьи с ошибочной работой Модуль:URL]]' end end return result end -- Более одной квадратной скобки — скорее всего, задано более одного URL — тоже возвращаем как есть. if select(2, string.gsub( arg1, "%[", "" )) > 1 then local result = arg1 if not isTestPage then result = result .. '[[Категория:Википедия:Статьи со сложным входом в Модуль:URL]]' if arg2 then -- Если есть arg2, а мы распарсить ссылку не смогли, и значит заменить title не сможем корректно, это есть ошибка. result = result .. '[[Категория:Википедия:Статьи с ошибочной работой Модуль:URL]]' end end return result end source = mw.text.trim( source, "%[%] " ) local titleDelimeterPosition = mw.ustring.find( source, " ", 1 ) if titleDelimeterPosition then if not title or title == "" then title = mw.ustring.sub( source, titleDelimeterPosition + 1 ) local postfixDelimeterPosition = mw.ustring.find( title, "%]", 1 ) if postfixDelimeterPosition then postfix = mw.ustring.sub( title, postfixDelimeterPosition + 1 ) title = mw.ustring.sub( title, 1, postfixDelimeterPosition - 1 ) end end source = mw.ustring.sub( source, 1, titleDelimeterPosition - 1 ) end local hostStartPosition local schemeDelimeterPosition = mw.ustring.find( source, "://", 1, true ) if schemeDelimeterPosition then scheme = mw.ustring.sub( source, 1, schemeDelimeterPosition + 2) hostStartPosition = schemeDelimeterPosition + 3 elseif mw.ustring.find( source, "^//", 1 ) then scheme = "//" hostStartPosition = 3 elseif mw.ustring.find( source, "^mailto:", 1 ) then scheme = "mailto:" hostStartPosition = 8 elseif mw.ustring.find( source, "@", 1 ) then scheme = "mailto:" source = scheme .. source hostStartPosition = 8 else scheme = "http://" source = scheme .. source hostStartPosition = 8 end if title then local finds = mw.ustring.find( arg1, "[", 1, true ) if titleDelimeterPosition and finds and finds > titleDelimeterPosition + 1 then -- Если titleDelimeterPosition промазал мимо скобки и нашел пробел раньше неё, к примеру "a [b c]", -- то свернуть всю нашу хиромантию и выдать первый аргумент без изменений. if arg2 == nil then return arg1 .. (isTestPage and '' or '[[Категория:Википедия:Статьи со сложным входом в Модуль:URL]]') -- Если есть arg2, а мы распарсить ссылку не смогли, и значит заменить title не сможем корректно, это есть ошибка. -- С другой стороны, если arg2 нет, а arg1 очень сложный, то возможно это нормальный ход вещей, -- и на вход в модуль дана уже очень сильно оформленная ссылка. else return arg1 .. (isTestPage and '' or '[[Категория:Википедия:Статьи с ошибочной работой Модуль:URL]]') end end return '[' .. source .. ' ' .. title .. ']' .. postfix end local hostDelimeterPosition = mw.ustring.find( source, "/", hostStartPosition, true ) if hostDelimeterPosition then host = mw.ustring.sub( source, hostStartPosition, hostDelimeterPosition - 1 ) if hostDelimeterPosition == mw.ustring.len( source ) then path = nil else path = mw.ustring.sub( source, hostDelimeterPosition + 1 ) end else host = mw.ustring.sub( source, hostStartPosition ) end -- post-split format options if startsWith( host, 'www.' ) then host = mw.ustring.sub( host, 5 ) end host = mw.language.new( 'en' ):lc( host ) if path and path ~= '' and path ~= '/' then local title = host .. '/' .. path if length and #title > length then title = host .. '/' .. mw.ustring.sub( path, 1, length - #title - 2 ) .. '…' end return '[' .. source .. ' ' .. title .. ']' .. postfix else return '[' .. source .. ' ' .. host .. ']' .. postfix end end function p.formatUrl( frame ) local url = frame.args[1] or '' local title = frame.args[2] or '' local length = frame.args['length'] and tonumber( frame.args['length'] ) url = mw.text.trim( url ) title = mw.text.trim( title ) if url == '' then return nil end if title == '' then title = nil end return formatUrlImpl( url, title, length ) end function p.formatUrlSingle( context, options, url ) url = mw.text.trim( url ) if url == '' then return nil end local title = nil if ( options['text'] and options['text'] ~= '' ) then title = options['text'] end local length = options['length'] and tonumber( options['length'] ) return formatUrlImpl( url, title, length ) end return p a991f879e135a472238c7f589e8d20d92a856d4d Шаблон:Langi 10 7 11 2017-10-14T07:25:47Z wikipedia:ru>Jack who built the house 0 → [[/doc]] wikitext text/x-wiki <span lang="{{{1}}}" xml:lang="{{{1}}}" style="font-style:italic;">{{{2}}}</span><noinclude>{{doc}}</noinclude> 7bb9f9098c88e770b982402adf30a3bbf645aa4b Шаблон:Lang-de 10 80 157 2017-12-10T06:47:23Z wikipedia:ru>Dima st bk 0 langi wikitext text/x-wiki [[Немецкий язык|нем.]]&nbsp;{{langi|de|{{{1}}}}}<noinclude>{{doc|Lang/doc}}</noinclude> 646eff5eb102894e6474a9c639b707a8ea39dc6e Модуль:Arguments 828 8 13 2018-01-12T21:01:04Z wikipedia:ru>Grain of sand 0 sandbox → песочница Scribunto text/plain -- This module provides easy processing of arguments passed to Scribunto from -- #invoke. It is intended for use by other Lua modules, and should not be -- called from #invoke directly. local libraryUtil = require('libraryUtil') local checkType = libraryUtil.checkType local arguments = {} -- Generate four different tidyVal functions, so that we don't have to check the -- options every time we call it. local function tidyValDefault(key, val) if type(val) == 'string' then val = val:match('^%s*(.-)%s*$') if val == '' then return nil else return val end else return val end end local function tidyValTrimOnly(key, val) if type(val) == 'string' then return val:match('^%s*(.-)%s*$') else return val end end local function tidyValRemoveBlanksOnly(key, val) if type(val) == 'string' then if val:find('%S') then return val else return nil end else return val end end local function tidyValNoChange(key, val) return val end local function matchesTitle(given, title) local tp = type( given ) return (tp == 'string' or tp == 'number') and mw.title.new( given ).prefixedText == title end local translate_mt = { __index = function(t, k) return k end } function arguments.getArgs(frame, options) checkType('getArgs', 1, frame, 'table', true) checkType('getArgs', 2, options, 'table', true) frame = frame or {} options = options or {} --[[ -- Set up argument translation. --]] options.translate = options.translate or {} if getmetatable(options.translate) == nil then setmetatable(options.translate, translate_mt) end if options.backtranslate == nil then options.backtranslate = {} for k,v in pairs(options.translate) do options.backtranslate[v] = k end end if options.backtranslate and getmetatable(options.backtranslate) == nil then setmetatable(options.backtranslate, { __index = function(t, k) if options.translate[k] ~= k then return nil else return k end end }) end --[[ -- Get the argument tables. If we were passed a valid frame object, get the -- frame arguments (fargs) and the parent frame arguments (pargs), depending -- on the options set and on the parent frame's availability. If we weren't -- passed a valid frame object, we are being called from another Lua module -- or from the debug console, so assume that we were passed a table of args -- directly, and assign it to a new variable (luaArgs). --]] local fargs, pargs, luaArgs if type(frame.args) == 'table' and type(frame.getParent) == 'function' then if options.wrappers then --[[ -- The wrappers option makes Module:Arguments look up arguments in -- either the frame argument table or the parent argument table, but -- not both. This means that users can use either the #invoke syntax -- or a wrapper template without the loss of performance associated -- with looking arguments up in both the frame and the parent frame. -- Module:Arguments will look up arguments in the parent frame -- if it finds the parent frame's title in options.wrapper; -- otherwise it will look up arguments in the frame object passed -- to getArgs. --]] local parent = frame:getParent() if not parent then fargs = frame.args else local title = parent:getTitle():gsub('/песочница$', '') local found = false if matchesTitle(options.wrappers, title) then found = true elseif type(options.wrappers) == 'table' then for _,v in pairs(options.wrappers) do if matchesTitle(v, title) then found = true break end end end -- We test for false specifically here so that nil (the default) acts like true. if found or options.frameOnly == false then pargs = parent.args end if not found or options.parentOnly == false then fargs = frame.args end end else -- options.wrapper isn't set, so check the other options. if not options.parentOnly then fargs = frame.args end if not options.frameOnly then local parent = frame:getParent() pargs = parent and parent.args or nil end end if options.parentFirst then fargs, pargs = pargs, fargs end else luaArgs = frame end -- Set the order of precedence of the argument tables. If the variables are -- nil, nothing will be added to the table, which is how we avoid clashes -- between the frame/parent args and the Lua args. local argTables = {fargs} argTables[#argTables + 1] = pargs argTables[#argTables + 1] = luaArgs --[[ -- Generate the tidyVal function. If it has been specified by the user, we -- use that; if not, we choose one of four functions depending on the -- options chosen. This is so that we don't have to call the options table -- every time the function is called. --]] local tidyVal = options.valueFunc if tidyVal then if type(tidyVal) ~= 'function' then error( "bad value assigned to option 'valueFunc'" .. '(function expected, got ' .. type(tidyVal) .. ')', 2 ) end elseif options.trim ~= false then if options.removeBlanks ~= false then tidyVal = tidyValDefault else tidyVal = tidyValTrimOnly end else if options.removeBlanks ~= false then tidyVal = tidyValRemoveBlanksOnly else tidyVal = tidyValNoChange end end --[[ -- Set up the args, metaArgs and nilArgs tables. args will be the one -- accessed from functions, and metaArgs will hold the actual arguments. Nil -- arguments are memoized in nilArgs, and the metatable connects all of them -- together. --]] local args, metaArgs, nilArgs, metatable = {}, {}, {}, {} setmetatable(args, metatable) local function mergeArgs(tables) --[[ -- Accepts multiple tables as input and merges their keys and values -- into one table. If a value is already present it is not overwritten; -- tables listed earlier have precedence. We are also memoizing nil -- values, which can be overwritten if they are 's' (soft). --]] for _, t in ipairs(tables) do for key, val in pairs(t) do if metaArgs[key] == nil and nilArgs[key] ~= 'h' then local tidiedVal = tidyVal(key, val) if tidiedVal == nil then nilArgs[key] = 's' else metaArgs[key] = tidiedVal end end end end end --[[ -- Define metatable behaviour. Arguments are memoized in the metaArgs table, -- and are only fetched from the argument tables once. Fetching arguments -- from the argument tables is the most resource-intensive step in this -- module, so we try and avoid it where possible. For this reason, nil -- arguments are also memoized, in the nilArgs table. Also, we keep a record -- in the metatable of when pairs and ipairs have been called, so we do not -- run pairs and ipairs on the argument tables more than once. We also do -- not run ipairs on fargs and pargs if pairs has already been run, as all -- the arguments will already have been copied over. --]] metatable.__index = function (t, key) --[[ -- Fetches an argument when the args table is indexed. First we check -- to see if the value is memoized, and if not we try and fetch it from -- the argument tables. When we check memoization, we need to check -- metaArgs before nilArgs, as both can be non-nil at the same time. -- If the argument is not present in metaArgs, we also check whether -- pairs has been run yet. If pairs has already been run, we return nil. -- This is because all the arguments will have already been copied into -- metaArgs by the mergeArgs function, meaning that any other arguments -- must be nil. --]] if type(key) == 'string' then key = options.translate[key] end local val = metaArgs[key] if val ~= nil then return val elseif metatable.donePairs or nilArgs[key] then return nil end for _, argTable in ipairs(argTables) do local argTableVal = tidyVal(key, argTable[key]) if argTableVal ~= nil then metaArgs[key] = argTableVal return argTableVal end end nilArgs[key] = 'h' return nil end metatable.__newindex = function (t, key, val) -- This function is called when a module tries to add a new value to the -- args table, or tries to change an existing value. if type(key) == 'string' then key = options.translate[key] end if options.readOnly then error( 'could not write to argument table key "' .. tostring(key) .. '"; the table is read-only', 2 ) elseif options.noOverwrite and args[key] ~= nil then error( 'could not write to argument table key "' .. tostring(key) .. '"; overwriting existing arguments is not permitted', 2 ) elseif val == nil then --[[ -- If the argument is to be overwritten with nil, we need to erase -- the value in metaArgs, so that __index, __pairs and __ipairs do -- not use a previous existing value, if present; and we also need -- to memoize the nil in nilArgs, so that the value isn't looked -- up in the argument tables if it is accessed again. --]] metaArgs[key] = nil nilArgs[key] = 'h' else metaArgs[key] = val end end local function translatenext(invariant) local k, v = next(invariant.t, invariant.k) invariant.k = k if k == nil then return nil elseif type(k) ~= 'string' or not options.backtranslate then return k, v else local backtranslate = options.backtranslate[k] if backtranslate == nil then -- Skip this one. This is a tail call, so this won't cause stack overflow return translatenext(invariant) else return backtranslate, v end end end metatable.__pairs = function () -- Called when pairs is run on the args table. if not metatable.donePairs then mergeArgs(argTables) metatable.donePairs = true end return translatenext, { t = metaArgs } end local function inext(t, i) -- This uses our __index metamethod local v = t[i + 1] if v ~= nil then return i + 1, v end end metatable.__ipairs = function (t) -- Called when ipairs is run on the args table. return inext, t, 0 end return args end return arguments e6be8dfccffa2057c3d50700f350d8d140c1dbf9 Шаблон:Join 10 60 117 2018-06-13T14:41:38Z wikipedia:ru>Jack who built the house 0 перевод на модуль wikitext text/x-wiki {{<includeonly>safesubst:</includeonly>#invoke:Separated entries|main|separator={{{separator|}}}}}<noinclude> {{doc}} <!-- Категории — на подстраницу /doc, интервики — в Викиданные. --> </noinclude> 92bb17b5322d3ae0ceab93d4dad3d31810d47eb0 Шаблон:До символа 10 53 103 2018-07-11T11:21:59Z wikipedia:ru>A particle for world to form 0 Для возможности использовать подстановку. wikitext text/x-wiki {{ {{{|safesubst:}}}#invoke:string2|bs|{{{1|}}}|{{{2|}}}|{{{from|1}}}}}<noinclude>{{doc}}</noinclude> 4cd51dc75d5f365cffac57c9577bd2b2f5c7cc3f Шаблон:Без начала 10 74 145 2018-07-11T22:30:39Z wikipedia:ru>A particle for world to form 0 Для возможности использовать подстановку. wikitext text/x-wiki {{<includeonly>safesubst:</includeonly>#ifeq:{{<includeonly>safesubst:</includeonly>Str_left|{{{1}}}|{{<includeonly>safesubst:</includeonly>#expr:{{<includeonly>safesubst:</includeonly>str len|{{{2}}}*}}-1}}}}*|{{{2}}}*|{{<includeonly>safesubst:</includeonly>Str_right|{{{1}}}|{{<includeonly>safesubst:</includeonly>#expr:{{<includeonly>safesubst:</includeonly>str len|{{{2}}}*}}-1}}}}|{{{1}}}}}<noinclude>{{doc}}</noinclude> 9fbca6f1fc236cb17fe77d76891e3f9c2afa2117 Шаблон:Str rightc 10 76 149 2018-07-11T22:33:58Z wikipedia:ru>A particle for world to form 0 Для возможности использовать подстановку. wikitext text/x-wiki {{<includeonly>safesubst:</includeonly>Str sub|{{{1}}}|{{<includeonly>safesubst:</includeonly>#expr:{{<includeonly>safesubst:</includeonly>Str len|{{{1}}}}}-{{{2}}}}}|{{{2}}}}}<noinclude>{{doc}}</noinclude> 0401d500dcc2224d44867ba0ea1f6c0fbeb758a0 Шаблон:Str left 10 42 81 2018-07-11T22:39:12Z wikipedia:ru>A particle for world to form 0 Для возможности использовать подстановку. wikitext text/x-wiki {{<includeonly>safesubst:</includeonly>padleft:|{{{2|1}}}|{{{1|}}}}}<noinclude> {{doc}} </noinclude> c1f57b63826f4d455dcaec8d2c24a2b8268f42ec Шаблон:Str sub 10 73 143 2018-09-29T20:45:02Z wikipedia:ru>TenBaseT 0 категории в документации wikitext text/x-wiki <includeonly>{{{{{|safesubst:}}}#invoke:String|sublength|s={{{1}}}|i={{{2|0}}}|len={{{3|0}}}}}</includeonly><noinclude> {{doc}} </noinclude> 3043790f8803e868cf6097b475fd58ba742887fe Шаблон:Lang-en2 10 63 123 2018-12-28T14:01:00Z wikipedia:ru>Dima st bk 0 Dima st bk переименовал страницу [[Шаблон:Langi-en2]] в [[Шаблон:Lang-en2]]: под стандарт wikitext text/x-wiki {{langi|en|{{{1}}}}}<noinclude> {{doc|Lang/doc}} </noinclude> 0471cf4d45a13ece481915d5c3e55db65d6aca04 Шаблон:No-doc 10 67 131 2019-01-17T08:39:04Z wikipedia:ru>Dima st bk 0 Защитил страницу [[Шаблон:No-doc]]: критический шаблон или модуль ([Редактирование=только автоподтверждённые] (бессрочно) [Переименование=только администраторы] (бессрочно)) wikitext text/x-wiki {{#ifeq: {{SUBPAGENAME}} | doc || {{#if: {{#if: {{yesno|{{{nocat|}}}}} | x }}{{#switch: {{NAMESPACE}} | {{ns:10}} | {{ns:828}} = | x }} || {{{1|}}} }} }}<noinclude>{{doc}}</noinclude> da013ca5b5f97f94bee392ff3a4488046f2ceac7 Шаблон:Заготовка шаблона 10 102 201 2019-04-25T13:33:44Z wikipedia:ru>QBA-bot 0 Защитил страницу [[Шаблон:Заготовка шаблона]]: критический шаблон или модуль (каскадная защита) ([Редактирование=только автоподтверждённые] (бессрочно) [Переименование=только автоподтверждённые] (бессрочно)) wikitext text/x-wiki {{#invoke:TemplateDataDoc|generateBlank|{{#if:{{{1|}}}|{{{1}}}|{{BASEPAGENAME}}}}|description={{{описание|}}}}}<noinclude>{{doc}}</noinclude> b451404244fd6898bc134564ddcb8941eca7f64a Шаблон:Карточка/Викитека 10 50 97 2019-06-16T22:57:42Z wikipedia:ru>Serhio Magpie 0 Удалять html теги и викификацию, чтобы не ломало форматирование ссылки. wikitext text/x-wiki {{#ifeq:{{{1|}}}|нельзя<!-- -->|© Произведения этого автора [[Свободный контент|несвободны]]<!-- -->|{{#if:{{#invoke:Wikidata/Interproject|getWikisourceLink|p103}}<!-- -->|[[Файл:wikisource-logo.svg|15px|Логотип Викитеки|link={{#invoke:Wikidata/Interproject|getWikisourceLink|p103}}]] [[{{#invoke:Wikidata/Interproject|getWikisourceLink|p103}}|{{#if:{{{2|}}}|{{удалить теги|{{delink|{{{2}}}}}}}|{{Сначала имя|{{PAGENAME}}}}}} в Викитеке]]<!-- -->|{{#if:{{{1|}}}|[[Файл:wikisource-logo.svg|15px|Логотип Викитеки|link=[[:s:{{{1|}}}]]]] [[:s:{{{1|}}}|{{#if:{{{2|}}}|{{удалить теги|{{delink|{{{2}}}}}}}|{{Сначала имя|{{PAGENAME}}}}}} в Викитеке]]}}<!-- -->}}<!-- -->{{#if:{{{nocat|}}}{{NAMESPACE}}||{{#if:{{{1|}}}|[[Категория:Википедия:Ссылка на Викитеку непосредственно в статье]]}}}}<!-- -->}}<noinclude> {{doc}} </noinclude> aac8463be78041fae4a55bf222430b207987f063 Модуль:TableTools 828 10 17 2019-08-26T06:20:31Z wikipedia:ru>Serhio Magpie 0 Обновлено с https://en.wikipedia.org/w/index.php?title=Module:TableTools&oldid=887403551 Scribunto text/plain --[[ ------------------------------------------------------------------------------------ -- TableTools -- -- -- -- This module includes a number of functions for dealing with Lua tables. -- -- It is a meta-module, meant to be called from other Lua modules, and should -- -- not be called directly from #invoke. -- ------------------------------------------------------------------------------------ --]] local libraryUtil = require('libraryUtil') local p = {} -- Define often-used variables and functions. local floor = math.floor local infinity = math.huge local checkType = libraryUtil.checkType local checkTypeMulti = libraryUtil.checkTypeMulti --[[ ------------------------------------------------------------------------------------ -- isPositiveInteger -- -- This function returns true if the given value is a positive integer, and false -- if not. Although it doesn't operate on tables, it is included here as it is -- useful for determining whether a given table key is in the array part or the -- hash part of a table. ------------------------------------------------------------------------------------ --]] function p.isPositiveInteger(v) if type(v) == 'number' and v >= 1 and floor(v) == v and v < infinity then return true else return false end end --[[ ------------------------------------------------------------------------------------ -- isNan -- -- This function returns true if the given number is a NaN value, and false -- if not. Although it doesn't operate on tables, it is included here as it is -- useful for determining whether a value can be a valid table key. Lua will -- generate an error if a NaN is used as a table key. ------------------------------------------------------------------------------------ --]] function p.isNan(v) if type(v) == 'number' and tostring(v) == '-nan' then return true else return false end end --[[ ------------------------------------------------------------------------------------ -- shallowClone -- -- This returns a clone of a table. The value returned is a new table, but all -- subtables and functions are shared. Metamethods are respected, but the returned -- table will have no metatable of its own. ------------------------------------------------------------------------------------ --]] function p.shallowClone(t) local ret = {} for k, v in pairs(t) do ret[k] = v end return ret end --[[ ------------------------------------------------------------------------------------ -- removeDuplicates -- -- This removes duplicate values from an array. Non-positive-integer keys are -- ignored. The earliest value is kept, and all subsequent duplicate values are -- removed, but otherwise the array order is unchanged. ------------------------------------------------------------------------------------ --]] function p.removeDuplicates(t) checkType('removeDuplicates', 1, t, 'table') local isNan = p.isNan local ret, exists = {}, {} for i, v in ipairs(t) do if isNan(v) then -- NaNs can't be table keys, and they are also unique, so we don't need to check existence. ret[#ret + 1] = v else if not exists[v] then ret[#ret + 1] = v exists[v] = true end end end return ret end --[[ ------------------------------------------------------------------------------------ -- numKeys -- -- This takes a table and returns an array containing the numbers of any numerical -- keys that have non-nil values, sorted in numerical order. ------------------------------------------------------------------------------------ --]] function p.numKeys(t) checkType('numKeys', 1, t, 'table') local isPositiveInteger = p.isPositiveInteger local nums = {} for k, v in pairs(t) do if isPositiveInteger(k) then nums[#nums + 1] = k end end table.sort(nums) return nums end --[[ ------------------------------------------------------------------------------------ -- affixNums -- -- This takes a table and returns an array containing the numbers of keys with the -- specified prefix and suffix. For example, for the table -- {a1 = 'foo', a3 = 'bar', a6 = 'baz'} and the prefix "a", affixNums will -- return {1, 3, 6}. ------------------------------------------------------------------------------------ --]] function p.affixNums(t, prefix, suffix) checkType('affixNums', 1, t, 'table') checkType('affixNums', 2, prefix, 'string', true) checkType('affixNums', 3, suffix, 'string', true) local function cleanPattern(s) -- Cleans a pattern so that the magic characters ()%.[]*+-?^$ are interpreted literally. s = s:gsub('([%(%)%%%.%[%]%*%+%-%?%^%$])', '%%%1') return s end prefix = prefix or '' suffix = suffix or '' prefix = cleanPattern(prefix) suffix = cleanPattern(suffix) local pattern = '^' .. prefix .. '([1-9]%d*)' .. suffix .. '$' local nums = {} for k, v in pairs(t) do if type(k) == 'string' then local num = mw.ustring.match(k, pattern) if num then nums[#nums + 1] = tonumber(num) end end end table.sort(nums) return nums end --[[ ------------------------------------------------------------------------------------ -- numData -- -- Given a table with keys like ("foo1", "bar1", "foo2", "baz2"), returns a table -- of subtables in the format -- { [1] = {foo = 'text', bar = 'text'}, [2] = {foo = 'text', baz = 'text'} } -- Keys that don't end with an integer are stored in a subtable named "other". -- The compress option compresses the table so that it can be iterated over with -- ipairs. ------------------------------------------------------------------------------------ --]] function p.numData(t, compress) checkType('numData', 1, t, 'table') checkType('numData', 2, compress, 'boolean', true) local ret = {} for k, v in pairs(t) do local prefix, num = mw.ustring.match(tostring(k), '^([^0-9]*)([1-9][0-9]*)$') if num then num = tonumber(num) local subtable = ret[num] or {} if prefix == '' then -- Positional parameters match the blank string; put them at the start of the subtable instead. prefix = 1 end subtable[prefix] = v ret[num] = subtable else local subtable = ret.other or {} subtable[k] = v ret.other = subtable end end if compress then local other = ret.other ret = p.compressSparseArray(ret) ret.other = other end return ret end --[[ ------------------------------------------------------------------------------------ -- compressSparseArray -- -- This takes an array with one or more nil values, and removes the nil values -- while preserving the order, so that the array can be safely traversed with -- ipairs. ------------------------------------------------------------------------------------ --]] function p.compressSparseArray(t) checkType('compressSparseArray', 1, t, 'table') local ret = {} local nums = p.numKeys(t) for _, num in ipairs(nums) do ret[#ret + 1] = t[num] end return ret end --[[ ------------------------------------------------------------------------------------ -- sparseIpairs -- -- This is an iterator for sparse arrays. It can be used like ipairs, but can -- handle nil values. ------------------------------------------------------------------------------------ --]] function p.sparseIpairs(t) checkType('sparseIpairs', 1, t, 'table') local nums = p.numKeys(t) local i = 0 local lim = #nums return function () i = i + 1 if i <= lim then local key = nums[i] return key, t[key] else return nil, nil end end end --[[ ------------------------------------------------------------------------------------ -- size -- -- This returns the size of a key/value pair table. It will also work on arrays, -- but for arrays it is more efficient to use the # operator. ------------------------------------------------------------------------------------ --]] function p.size(t) checkType('size', 1, t, 'table') local i = 0 for k in pairs(t) do i = i + 1 end return i end local function defaultKeySort(item1, item2) -- "number" < "string", so numbers will be sorted before strings. local type1, type2 = type(item1), type(item2) if type1 ~= type2 then return type1 < type2 else -- This will fail with table, boolean, function. return item1 < item2 end end --[[ Returns a list of the keys in a table, sorted using either a default comparison function or a custom keySort function. ]] function p.keysToList(t, keySort, checked) if not checked then checkType('keysToList', 1, t, 'table') checkTypeMulti('keysToList', 2, keySort, { 'function', 'boolean', 'nil' }) end local list = {} local index = 1 for key, value in pairs(t) do list[index] = key index = index + 1 end if keySort ~= false then keySort = type(keySort) == 'function' and keySort or defaultKeySort table.sort(list, keySort) end return list end --[[ Iterates through a table, with the keys sorted using the keysToList function. If there are only numerical keys, sparseIpairs is probably more efficient. ]] function p.sortedPairs(t, keySort) checkType('sortedPairs', 1, t, 'table') checkType('sortedPairs', 2, keySort, 'function', true) local list = p.keysToList(t, keySort, true) local i = 0 return function() i = i + 1 local key = list[i] if key ~= nil then return key, t[key] else return nil, nil end end end --[[ Returns true if all keys in the table are consecutive integers starting at 1. --]] function p.isArray(t) checkType("isArray", 1, t, "table") local i = 0 for k, v in pairs(t) do i = i + 1 if t[i] == nil then return false end end return true end -- { "a", "b", "c" } -> { a = 1, b = 2, c = 3 } function p.invert(array) checkType("invert", 1, array, "table") local map = {} for i, v in ipairs(array) do map[v] = i end return map end --[[ { "a", "b", "c" } -> { ["a"] = true, ["b"] = true, ["c"] = true } --]] function p.listToSet(t) checkType("listToSet", 1, t, "table") local set = {} for _, item in ipairs(t) do set[item] = true end return set end --[[ Recursive deep copy function. Preserves identities of subtables. ]] local function _deepCopy(orig, includeMetatable, already_seen) -- Stores copies of tables indexed by the original table. already_seen = already_seen or {} local copy = already_seen[orig] if copy ~= nil then return copy end if type(orig) == 'table' then copy = {} for orig_key, orig_value in pairs(orig) do copy[deepcopy(orig_key, includeMetatable, already_seen)] = deepcopy(orig_value, includeMetatable, already_seen) end already_seen[orig] = copy if includeMetatable then local mt = getmetatable(orig) if mt ~= nil then local mt_copy = deepcopy(mt, includeMetatable, already_seen) setmetatable(copy, mt_copy) already_seen[mt] = mt_copy end end else -- number, string, boolean, etc copy = orig end return copy end function p.deepCopy(orig, noMetatable, already_seen) checkType("deepCopy", 3, already_seen, "table", true) return _deepCopy(orig, not noMetatable, already_seen) end --[[ Concatenates all values in the table that are indexed by a number, in order. sparseConcat{ a, nil, c, d } => "acd" sparseConcat{ nil, b, c, d } => "bcd" ]] function p.sparseConcat(t, sep, i, j) local list = {} local list_i = 0 for _, v in p.sparseIpairs(t) do list_i = list_i + 1 list[list_i] = v end return table.concat(list, sep, i, j) end --[[ -- This returns the length of a table, or the first integer key n counting from -- 1 such that t[n + 1] is nil. It is similar to the operator #, but may return -- a different value when there are gaps in the array portion of the table. -- Intended to be used on data loaded with mw.loadData. For other tables, use #. -- Note: #frame.args in frame object always be set to 0, regardless of -- the number of unnamed template parameters, so use this function for -- frame.args. --]] function p.length(t) local i = 1 while t[i] ~= nil do i = i + 1 end return i - 1 end function p.inArray(arr, valueToFind) checkType("inArray", 1, arr, "table") -- if valueToFind is nil, error? for _, v in ipairs(arr) do if v == valueToFind then return true end end return false end return p fe918509f168332267834b3a6f5c219a9de5b2e7 Шаблон:Флагификация 10 41 79 2019-09-27T22:34:05Z wikipedia:ru>Serhio Magpie 0 Отслеживающая категория в случаях, когда в качестве параметра приходит викиссылки или html wikitext text/x-wiki {{#if: {{{1|}}} | {{#switch: {{str left|{{{1|}}}|1}} | [ | < | { = [[Категория:Википедия:Страницы с неверным параметром шаблона Флагификация]] | #default = {{Флагификация/{{{1|}}} | Флагификация/флагификация | variant = {{{variant|{{{2|}}}}}} | размер = {{{размер|}}} }} }} }}<noinclude>{{doc}}</noinclude> 46f4b3bb9842eaf2c75057227b1b76b565563be5 Шаблон:Tl 10 72 141 2019-10-20T16:35:32Z wikipedia:ru>Helgo13 0 Helgo13 переименовал страницу [[Шаблон:T]] в [[Шаблон:Tl]] wikitext text/x-wiki {{{{{|safesubst:}}}#invoke: Template call code | withoutParams }}<noinclude>{{doc}}</noinclude> 61fe4d068895a5e7e5802767f5d7df71a7561c57 Шаблон:Карточка/внизу 10 29 55 2019-11-13T23:18:52Z wikipedia:ru>Serhio Magpie 0 Перенесено в общие стили wikitext text/x-wiki <includeonly>{{#if:{{{внизу|}}}|<tr><td colspan="2" class="infobox-below {{{класс_внизу|}}}" style="{{{стиль_внизу_общий|}}};{{{стиль_внизу|}}}">{{{внизу|}}}</td></tr>}}</includeonly><noinclude> {{doc}} </noinclude> 169fb2d10b0847c2fd677eda9f159ba99025198f Модуль:String2 828 58 113 2020-02-07T22:56:05Z wikipedia:ru>Serhio Magpie 0 + ucfirst Scribunto text/plain --[[ Кое-какие дополнительные функции для строк ]] local M = { bs=function(f)-- первый параметр до начала второго параметра (или до конца, если он не встретился) --необяз. 3-й параметр - с какого по номеру (с 1) символа начинать поиск. return mw.ustring.sub(f.args[1], 1, (mw.ustring.find(f.args[1],f.args[2],tonumber(f.args[3] or 1),true) or 0)-1) end; as=function(f)-- первый параметр после начала второго параметра return mw.ustring.sub(f.args[1], (mw.ustring.find(f.args[1],f.args[2],1,true) or 0)+1) end; Tr=function(s,f,t,cf,df,sf)-- транслитерация первого параметра путём замены символов из второго параметра символами из третьего. -- Отдельными параметрами можно передавать флаги c, d и s, как в Perl; диапазоны в замене не работают, только в левой части -- (т.е. дефис надо передавать первым или последним). Второй результат - число заменённых символов local r, l, l2 = {}, mw.ustring.len(f), mw.ustring.len(t); for i = 1, l do r[mw.ustring.sub(f,i,i)] = i<=l2 and mw.ustring.sub(t,i,i) or df and '' or mw.ustring.sub(t,l2,l2) end local n2=0; local res, n = mw.ustring.gsub( s, ('[%s%s]%s'):format( cf and '^' or '', f:gsub('%','%%'):gsub(']','%]'):gsub('^%^','%^'), sf and '+' or '' ), sf and function(cc) n2 = n2+mw.ustring.len(cc)-1; return mw.ustring.gsub(cc,'.',r) end or r ) return res, n+n2 end; -- tr = function(f) return (M.Tr(f.args[1],f.args[2],f.args[3],f.args['c'],f.args['d'],f.args['s'])) end;-- транслитерировать -- trс = function(f) return ({M.Tr(f.args[1],f.args[2],f.args[3],f.args['c'],f.args['d'],f.args['s'])})[2] end;-- посчитать символы Trg = function(s,t,f,fi)-- Производит замену строк произвольной длины (если с fi, регистр не учитывает). -- Приоритет - по порядку в таблицах. for n,p in ipairs(t) do t[n] = {fi and mw.ustring.upper(p) or p,mw.ustring.len(p)} end local r,i,l,N = {},1,mw.ustring.len(s),0 while i<=l do (function() for n,p in ipairs(t) do if ( fi and mw.ustring.upper(mw.ustring.sub(s,i,i+p[2]-1)) or mw.ustring.sub(s,i,i+p[2]-1) ) == p[1] then table.insert(r,f[n]); i = i+p[2]; N=N+1; return end end table.insert(r,mw.ustring.sub(s,i,i)); i=i+1; return end)() end return table.concat(r),N end; trg = function(frame)--Работает с номерными аргументами шаблона,если задан параметр u, иначе со своими. -- Заменяет в первом аргументе аргументы 2, 4, 6... на аргументы 3, 5, 7... local tf, t, f, i= frame.args['u'] and frame.getParent() or f, {}, {}, 1; while tf.args[2*i] do t[tf.args[2*i]]=tf.args[2*i+1] or '' end return ( M.Trg(tf.args[1],t,f,(frame.args['i'] or '')~='') ) end; join = function (f) --объединяет нумерованные аргументы вызвавшего шаблона -- от from или 1 до to или первого отсутствующего -- через первый параметр invoke. Последний элемент можно присоединять иначе, задав второй параметр. -- По умолчанию ',' & 'и' -- Если 3-й параметр invoke — "s", строки из пробелов игнорируются; если "_", игнорируются пустые строки local t, tf, i = {}, f:getParent(), tonumber(f.args.from) or 1 local k,j,m = tonumber(f.args.to),i,f.args[3] while k and i<=k or tf.args[i] do if ( ({ ['_']=function(s)return s~=''end; ['s']=function(s)return not tostring(s):match("^%s*$")end })[m] or function() return true end )(tf.args[i]) then t[j]=tf.args[i]; j=j+1 end; i=i+1 end return mw.text.listToText(t,f.args[1],f.args[2] or f.args[1]) end } function M.formatRound(frame) --форматирует число, чтобы оно имело order знаков после запятой return string.format("%0."..frame.args[2].."f",tonumber(frame.args[1])); end -- если строка s содержит число, увеличивает первое такое число на n, иначе возращает пустую строку. -- если число начинается на 0, то увеличенное число будет содержать по крайне мере столько цифр сколько исходное. function M.increase(s, n) local a,b,c = string.match(s, "([^0-9]*)([0-9]+)(.*)") if b==nil then return s end local num = tonumber(b) + n if b:sub(1,1)=='0' then b = string.format("%0"..b:len().."d", num) else b=num end return a .. b .. c end function M.ucfirst(frame ) local s = mw.text.trim( frame.args[1] or "" ) local s1 = "" -- if it's a list chop off and (store as s1) everything up to the first <li> local lipos = string.find(s, "<li>" ) if lipos then s1 = string.sub(s, 1, lipos + 3) s = string.sub(s, lipos + 4) end -- s1 is either "" or the first part of the list markup, so we can continue -- and prepend s1 to the returned string local letterpos if string.find(s, "^%[%[[^|]+|[^%]]+%]%]") then -- this is a piped wikilink, so we capitalise the text, not the pipe local _ _, letterpos = string.find(s, "|%A*%a") -- find the first letter after the pipe else letterpos = string.find(s, '%a') end if letterpos then local first = string.sub(s, 1, letterpos - 1) local letter = string.sub(s, letterpos, letterpos) local rest = string.sub(s, letterpos + 1) return s1 .. first .. string.upper(letter) .. rest else return s1 .. s end end return M 1d51eb45a573b689485dad672c0968c18ec3b342 Модуль:Separated entries 828 69 135 2020-07-05T06:33:20Z wikipedia:ru>Serhio Magpie 0 + newline Scribunto text/plain -- This module takes positional parameters as input and concatenates them with -- an optional separator. The final separator (the "conjunction") can be -- specified independently, enabling natural-language lists like -- "foo, bar, baz and qux". local compressSparseArray = require('Module:TableTools').compressSparseArray local p = {} function p._main(args) local separator = args.separator -- Decode (convert to Unicode) HTML escape sequences, such as "&#32;" for space. and mw.text.decode(args.separator) or '' local conjunction = args.conjunction and mw.text.decode(args.conjunction) or separator -- Discard named parameters. local values = compressSparseArray(args) return mw.text.listToText(values, separator, conjunction) end local function makeInvokeFunction(separator, conjunction) return function (frame) local args = require('Module:Arguments').getArgs(frame) args.separator = separator or args.separator args.conjunction = conjunction or args.conjunction return p._main(args) end end p.main = makeInvokeFunction() p.br = makeInvokeFunction('<br />') p.newline = makeInvokeFunction('\n') p.comma = makeInvokeFunction(mw.message.new('comma-separator'):plain()) return p 33a68f0a46d62c42b6523a548f0f881e82ecfe58 Модуль:Transclude 828 36 69 2020-11-17T12:38:34Z wikipedia:ru>Wikisaurus 0 пропускать пустые параметры в forall и join Scribunto text/plain local p={} -- Вызывает внутренний шаблон с аргументами объемлющего шаблона function p.call(frame) local template = frame.args[1] local args = frame:getParent().args return frame:expandTemplate{ title=template, args=args } end -- Общая реализация для forall и call local function forallImpl(args, separator, conjunction, func) -- нумерованные ключи из args local keys = {} -- перебор в произвольном порядке, даже для нумерованных ключей for key, value in pairs(args) do if type(key) == 'number' and value and value ~= '' then table.insert(keys, key) end end table.sort(keys) local results = {} for _, key in ipairs(keys) do local value = func(args[key]) table.insert(results, value) end return mw.text.listToText(results, separator, conjunction) end -- Вызывает внутренний шаблон, передавая ему нумерованные параметры объемлющего шаблона по-одному function p.forall(frame) local template = frame.args[1] local separator = frame.args.separator or '' local conjunction = frame.args.conjunction or separator local args = frame:getParent().args local func = function(value) return frame:expandTemplate{ title = template, args = {value} } -- или другой frame? end return forallImpl(args, separator, conjunction, func) end -- Берёт нумерованные аргументы объемлющего шаблона и склеивает их в единую строку function p.join(frame) local separator = frame.args[1] or '' local conjunction = frame.args[2] or separator local args = frame:getParent().args local func = function(value) return value end return forallImpl(args, separator, conjunction, func) end -- Служебная функция: удаляет дубликаты из отсортированного массива с нумерованными индексами local function deleteDuplicates(args) local res = {} for key, value in pairs(args) do if args[key+1] ~= value then table.insert(res, value) end end return res end -- Вызывает внутренний шаблон несколько раз, передавая в него блоки аргументов объемлющего шаблона function p.npc(frame) local args = frame:getParent().args local templateFrame = frame:getParent() local template = frame.args[1] -- определение, блоки аргументов с какими номерами нужны: -- если в объемлющем шаблоне есть "параметр12" и в вызове модуля есть "параметр", то вызывается 12-й блок local nums = {} for key, _ in pairs(args) do local main, num = string.match(key, '^(.-)%s*(%d*)$') num = tonumber(num) -- учитывать "параметр12", только если задано "параметр" if num and frame.args[main] then table.insert(nums, num) end end table.sort(nums) nums = deleteDuplicates(nums) -- проходить по нужным номерам блоков по возрастанию и однократно -- подставлять в шаблон: -- 1. общие аргументы данного модуля -- 2. аргументы объемлющего шаблона вида "параметр12" как "параметр" в 12-й блок local results = {} for _, blockNum in ipairs(nums) do -- общие аргументы модуля, которые передаются в каждый блок local blockArgs = mw.clone(frame.args) -- metatable ломает expandTemplate setmetatable(blockArgs, nil) for key, value in pairs(args) do local main, num = string.match(key, '^(.-)%s*(%d*)$') num = tonumber(num) -- передавать "параметр12" как "параметр" в 12-й блок, только если есть "параметр" в вызове модуля if blockNum == num and frame.args[main] then blockArgs[main] = value end end local blockText = templateFrame:expandTemplate{ title=template; args=blockArgs } table.insert(results, blockText) end return table.concat(results) end -- Действует аналогично forall по числовой переменной, изменяющейся (по умолчанию, от 1) до f.args[2]. function p.cycle(f) local tf,ac,op=f:getParent(), {}, f.args.output or 'inline'; local sep=''; if op == 'newline' then sep='\n'; end for p,k in pairs(f.args) do if type(p)=='number' then if p>2 then ac[p-1]=k end else ac[p]=k end end local s,fh = f.args[2]:match('^%s*(%-?%d+)%s*%.%.') or 1, f.args[2]:match('%.%.%s*(%S.*)%s*$') or f.args[2] or ''; fh=tonumber(fh) or fh:match('^%s*(.-)%s*$'); s=tonumber(s); local acr={}; if not s then error('Начало цикла «'..s..'» — не число') end local function dc(order) local r=tf:expandTemplate{ title=f.args[1]; args={s,unpack(ac)} } if order == 'desc' then s=s-1; else s=s+1; end if r~='' then table.insert(acr,r); return r end end if type(fh)=='number' then if fh > s then while s<=fh do dc('asc') end else while s>=fh do dc('desc') end end elseif fh~='' then while tf:expandTemplate{ title=fh; args={s,unpack(ac)} } do dc('asc') end else while dc('asc') do end end return table.concat(acr, sep) end return p c17cfab4cebc23157f5ab8d18c7e4f5c273bfa59 Модуль:Hash 828 79 155 2021-02-07T10:01:11Z wikipedia:ru>Grain of sand 0 + list() для вывода списка доступных алгоритмов Scribunto text/plain local getArgs = require('Module:Arguments').getArgs local p = {} local function inTable(table, value) for k, v in pairs(table) do if v == value then return true end end return false end function p.list(frame) return table.concat(mw.hash.listAlgorithms(), '; ') end function p.main(frame) local args = getArgs(frame, { frameOnly = true }) local algorithm if not args[1] then return '<span class="error">Не указана строка для хеширования.</span>' end if args[2] then if not inTable(mw.hash.listAlgorithms(), args[2]) then return '<span class="error">Алгоритм хеширования ' .. args[2] .. ' не поддерживается, или вы неточно указали его имя. Используйте функцию <kbd>mw.hash.listAlgorithms()</kbd> для получения списка доступных алгоритмов.</span>' end algorithm = args[2] else -- Алгоритм выбран из соображений быстродействия (см. [[:en:Fowler–Noll–Vo hash function]]), -- 64-битная функция используется для уменьшения вероятности коллизий до пренебрежимо малой -- величины. Возможно, есть лучшая опция — проверяйте. algorithm = 'fnv164' end return mw.hash.hashValue(algorithm, args[1]) end return p 5d18513e574435f191164695449a620b031f93ec Модуль:Infocards/dateCat 828 56 109 2021-02-14T08:16:01Z wikipedia:ru>WindEwriX 0 Защитил страницу [[Модуль:Infocards/dateCat]]: критический шаблон или модуль: включён в [[Модуль:Wikidata/date]] и [[Модуль:Infocards]] ([Редактирование=администраторы и инженеры] (бессрочно) [Переименование=администраторы и инженеры] (бессрочно)) Scribunto text/plain local p = {} p.categoryUnknownBirthDate = '[[Категория:Персоналии, чья дата рождения не установлена]]' p.categoryUnknownDeathDate = '[[Категория:Персоналии, чья дата смерти не установлена]]' p.categoryBigCurrentAge = '[[Категория:Персоналии с большим текущим возрастом]]' --бывш. [[Категория:Википедия:Статьи о персоналиях с большим текущим возрастом]] p.categoryNegativeAge = '[[Категория:Персоналии с отрицательным возрастом]]' -- p.categoryBigDeathAge = '[[Категория:Википедия:Статьи о персоналиях с большим возрастом во время смерти]]' //deleted -d.bratchuk 05-07-2016 p.categoryBiographiesOfLivingPersons = '[[Категория:Википедия:Биографии современников]]' p.categoryRecentlyDeceased = '[[Категория:Персоналии, умершие менее года назад]]' p.categoryManualWikification = '[[Категория:Википедия:Статьи с ручной викификацией дат в карточке]]' p.categoryNoBirthDate = '[[Категория:Персоналии без указанной даты рождения]]' --бывш. [[Категория:Википедия:Персоны без указанной даты рождения]] return p 6b27e44bc0a4aaafa42074ca16db92b13e4999d4 Шаблон:Doc/end 10 87 171 2021-02-14T18:18:13Z wikipedia:ru>Putnik 0 для модулей предзагрузка нормально не работает wikitext text/x-wiki <includeonly></div> </div><templatestyles src="Шаблон:Doc/styles.css" />{{#ifexpr: {{NAMESPACENUMBER}} mod 2 = 1 <!-- Например, [[Обсуждение MediaWiki:Robots.txt]] --> | {{^|1em}} | <div class="ts-doc-footer plainlinks"> {{#ifeq: {{str left|{{PAGENAME}}|9}} | Песочница | | {{#ifeq: {{str rightc|{{PAGENAME}}|10}} | /песочница | | Во избежание поломок страниц, использующих этот {{#ifeq: {{NAMESPACE}} | Модуль | модуль | шаблон }}, экспериментируйте в [[Википедия:Правка и тестирование шаблонов в песочнице|песочнице]] <small style="font-style:normal;">({{#ifexist: {{FULLPAGENAME}}/песочница | [{{fullurl:{{FULLPAGENAME}}/песочница|action=edit}} редактировать] {{!}} [{{fullurl:Special:ComparePages|page1={{FULLPAGENAMEE}}&page2={{FULLPAGENAMEE}}/песочница}} разница] {{#ifexist: {{FULLPAGENAME}}/тесты | {{!}} [[{{FULLPAGENAME}}/тесты|тесты]] }} | {{#ifeq: {{NAMESPACE}} | Модуль | [{{fullurl:{{FULLPAGENAME}}/песочница|action=edit}} создать] | [{{fullurl:{{FULLPAGENAME}}/песочница|action=edit&preload=Шаблон:Doc/предзагрузка-песочница}} создать] {{!}} [{{fullurl:{{FULLPAGENAME}}/песочница|action=edit&preload=Шаблон:Doc/зеркало}} зеркало] }} }})</small> или {{#ifeq: {{NAMESPACE}} | Модуль | [[Модуль:Песочница|песочнице для модулей]] | своём [[ВП:ЛП|личном пространстве]] }}.<br> }} }}{{#ifexist: {{FULLPAGENAME}}/doc | Пожалуйста, добавляйте категории на подстраницу [[/doc]].&#32;}}[[Special:PrefixIndex/{{FULLPAGENAME}}/|Подстраницы этого {{#ifeq: {{NAMESPACE}} | Модуль | модуля | шаблона }}]]. </div> }}</includeonly><noinclude>{{doc}}</noinclude> 758a01a3d76e14ef14b2b0ee047ac47ddac8fd8e Шаблон:Пример с именами параметров 10 107 211 2021-02-28T18:08:15Z wikipedia:ru>Grain of sand 0 Grain of sand переименовал страницу [[Шаблон:Parameter names example]] в [[Шаблон:Пример с именами параметров]]: русификация wikitext text/x-wiki <includeonly>{{#invoke:Parameter names example|main}}</includeonly><noinclude> {{Doc}} </noinclude> 2118cbf70aef4a440190a91ba85327a5cb8d3808 Шаблон:Parameter names example 10 109 215 2021-02-28T18:08:16Z wikipedia:ru>Grain of sand 0 Grain of sand переименовал страницу [[Шаблон:Parameter names example]] в [[Шаблон:Пример с именами параметров]]: русификация wikitext text/x-wiki #перенаправление [[Шаблон:Пример с именами параметров]] f42e4b1940da05c9e876c1c77cffa5c78e59c68d Модуль:Color contrast 828 64 125 2021-03-01T22:40:23Z wikipedia:ru>Grain of sand 0 local Scribunto text/plain -- -- This module implements -- {{Color contrast ratio}} -- {{Greater color contrast ratio}} -- {{ColorToLum}} -- {{RGBColorToLum}} -- local p = {} local HTMLcolor = mw.loadData( 'Module:Color contrast/colors' ) local function sRGB ( v ) if (v <= 0.03928) then v = v / 12.92 else v = math.pow((v+0.055)/1.055, 2.4) end return v end local function rgbdec2lum( R, G, B ) if ( 0 <= R and R < 256 and 0 <= G and G < 256 and 0 <= B and B < 256 ) then return 0.2126 * sRGB(R/255) + 0.7152 * sRGB(G/255) + 0.0722 * sRGB(B/255) else return '' end end local function hsl2lum( h, s, l ) if ( 0 <= h and h < 360 and 0 <= s and s <= 1 and 0 <= l and l <= 1 ) then local c = (1 - math.abs(2*l - 1))*s local x = c*(1 - math.abs( math.fmod(h/60, 2) - 1) ) local m = l - c/2 local r, g, b = m, m, m if( 0 <= h and h < 60 ) then r = r + c g = g + x elseif( 60 <= h and h < 120 ) then r = r + x g = g + c elseif( 120 <= h and h < 180 ) then g = g + c b = b + x elseif( 180 <= h and h < 240 ) then g = g + x b = b + c elseif( 240 <= h and h < 300 ) then r = r + x b = b + c elseif( 300 <= h and h < 360 ) then r = r + c b = b + x end return rgbdec2lum(255*r, 255*g, 255*b) else return '' end end local function color2lum( c ) if (c == nil) then return '' end -- whitespace c = c:match( '^%s*(.-)[%s;]*$' ) -- lowercase c = c:lower() -- first try to look it up local L = HTMLcolor[c] if (L ~= nil) then return L end -- convert from hsl if mw.ustring.match(c,'^hsl%([%s]*[0-9][0-9%.]*[%s]*,[%s]*[0-9][0-9%.]*%%[%s]*,[%s]*[0-9][0-9%.]*%%[%s]*%)$') then local h, s, l = mw.ustring.match(c,'^hsl%([%s]*([0-9][0-9%.]*)[%s]*,[%s]*([0-9][0-9%.]*)%%[%s]*,[%s]*([0-9][0-9%.]*)%%[%s]*%)$') return hsl2lum(tonumber(h), tonumber(s)/100, tonumber(l)/100) end -- convert from rgb if mw.ustring.match(c,'^rgb%([%s]*[0-9][0-9]*[%s]*,[%s]*[0-9][0-9]*[%s]*,[%s]*[0-9][0-9]*[%s]*%)$') then local R, G, B = mw.ustring.match(c,'^rgb%([%s]*([0-9][0-9]*)[%s]*,[%s]*([0-9][0-9]*)[%s]*,[%s]*([0-9][0-9]*)[%s]*%)$') return rgbdec2lum(tonumber(R), tonumber(G), tonumber(B)) end -- convert from rgb percent if mw.ustring.match(c,'^rgb%([%s]*[0-9][0-9%.]*%%[%s]*,[%s]*[0-9][0-9%.]*%%[%s]*,[%s]*[0-9][0-9%.]*%%[%s]*%)$') then local R, G, B = mw.ustring.match(c,'^rgb%([%s]*([0-9][0-9%.]*)%%[%s]*,[%s]*([0-9][0-9%.]*)%%[%s]*,[%s]*([0-9][0-9%.]*)%%[%s]*%)$') return rgbdec2lum(255*tonumber(R)/100, 255*tonumber(G)/100, 255*tonumber(B)/100) end -- remove leading # (if there is one) and whitespace c = mw.ustring.match(c, '^[%s#]*([a-f0-9]*)[%s]*$') -- split into rgb local cs = mw.text.split(c or '', '') if( #cs == 6 ) then local R = 16*tonumber('0x' .. cs[1]) + tonumber('0x' .. cs[2]) local G = 16*tonumber('0x' .. cs[3]) + tonumber('0x' .. cs[4]) local B = 16*tonumber('0x' .. cs[5]) + tonumber('0x' .. cs[6]) return rgbdec2lum(R, G, B) elseif ( #cs == 3 ) then local R = 16*tonumber('0x' .. cs[1]) + tonumber('0x' .. cs[1]) local G = 16*tonumber('0x' .. cs[2]) + tonumber('0x' .. cs[2]) local B = 16*tonumber('0x' .. cs[3]) + tonumber('0x' .. cs[3]) return rgbdec2lum(R, G, B) end -- failure, return blank return '' end function p._greatercontrast(args) local bias = tonumber(args['bias'] or '0') or 0 local v1 = color2lum(args[1] or '') local c2 = args[2] or '#FFFFFF' local v2 = color2lum(c2) local c3 = args[3] or '#000000' local v3 = color2lum(c3) local ratio1 = 0; local ratio2 = 0; if (type(v1) == 'number' and type(v2) == 'number') then ratio1 = (v2 + 0.05)/(v1 + 0.05) ratio1 = (ratio1 < 1) and 1/ratio1 or ratio1 end if (type(v1) == 'number' and type(v3) == 'number') then ratio2 = (v3 + 0.05)/(v1 + 0.05) ratio2 = (ratio2 < 1) and 1/ratio2 or ratio2 end return (ratio1 + bias > ratio2) and c2 or c3 end function p._ratio(args) local v1 = color2lum(mw.text.unstripNoWiki(args[1] or '')) local v2 = color2lum(mw.text.unstripNoWiki(args[2] or '')) if (type(v1) == 'number' and type(v2) == 'number') then -- v1 should be the brighter of the two. if v2 > v1 then v1, v2 = v2, v1 end return (v1 + 0.05)/(v2 + 0.05) else return args['error'] or '?' end end function p._styleratio(args) local style = (args[1] or ''):lower() local bg, fg = 'white', '#202122' local lum_bg, lum_fg = 1, 0.016 if args[2] then local lum = color2lum(args[2]) if lum ~= '' then bg, lum_bg = args[2], lum end end if args[3] then local lum = color2lum(args[3]) if lum ~= '' then fg, lum_fg = args[3], lum end end local slist = mw.text.split(style or '', ';') for k = 1, #slist do local s = slist[k] local k, v = s:match( '^[%s]*([^:]-):([^:]-)[%s;]*$' ) k = k or '' v = v or '' if (k:match('^[%s]*(background)[%s]*$') or k:match('^[%s]*(background%-color)[%s]*$')) then local lum = color2lum(v) if( lum ~= '' ) then bg, lum_bg = v, lum end elseif (k:match('^[%s]*(color)[%s]*$')) then local lum = color2lum(v) if( lum ~= '' ) then bg, lum_fg = v, lum end end end if lum_bg > lum_fg then return (lum_bg + 0.05)/(lum_fg + 0.05) else return (lum_fg + 0.05)/(lum_bg + 0.05) end end function p.lum(frame) return color2lum(frame.args[1] or frame:getParent().args[1]) end function p.ratio(frame) local args = frame.args[1] and frame.args or frame:getParent().args return p._ratio(args) end function p.styleratio(frame) local args = frame.args[1] and frame.args or frame:getParent().args return p._styleratio(args) end function p.greatercontrast(frame) local args = frame.args[1] and frame.args or frame:getParent().args return p._greatercontrast(args) end return p cce580326bee8eaf3c81df6c76c04a9a2909dfa2 Модуль:Parameter names example 828 108 213 2021-03-03T19:37:12Z wikipedia:ru>Grain of sand 0 шаблон переименован Scribunto text/plain -- This module implements {{parameter names example}}. local p = {} local function makeParam(s) local lb = '&#123;' local rb = '&#125;' return lb:rep(3) .. s .. rb:rep(3) end local function italicize(s) return "''" .. s .. "''" end local function plain(s) return s end function p._main(args, frame) -- Find how we want to format the arguments to the template. local formatFunc if args._display == 'italics' or args._display == 'italic' then formatFunc = italicize elseif args._display == 'plain' then formatFunc = plain else formatFunc = makeParam end -- Build the table of template arguments. local targs = {} for k, v in pairs(args) do if type(k) == 'number' then targs[v] = formatFunc(v) elseif not k:find('^_') then targs[k] = v end end -- Find the template name. local template if args._template then template = args._template else local currentTitle = mw.title.getCurrentTitle() if currentTitle.prefixedText:find('/sandbox$') or currentTitle.prefixedText:find('/песочница$') then template = currentTitle.prefixedText else template = currentTitle.basePageTitle.prefixedText end end -- Call the template with the arguments. frame = frame or mw.getCurrentFrame() local success, result = pcall( frame.expandTemplate, frame, {title = template, args = targs} ) if success then return result else return '' end end function p.main(frame) local args = require('Module:Arguments').getArgs(frame, { wrappers = 'Шаблон:Пример с именами параметров' }) return p._main(args, frame) end return p 64667ee447347f717db659027d7c4ec864230a93 Шаблон:Wikidata 10 26 49 2021-04-01T12:24:50Z wikipedia:ru>MBH 0 [[ВП:Откат|откат]] правок [[Special:Contribs/Lê Lợi (bot)|Lê Lợi (bot)]] ([[UT:Lê Lợi (bot)|обс.]]) к версии Wikisaurus wikitext text/x-wiki <includeonly>{{#invoke:Wikidata|formatProperty|property={{{1|}}}|value={{{2|}}}}}</includeonly><noinclude>{{doc}}</noinclude> 9d3d422eca39504b018df6ec0bb047392a7aba7e Модуль:Infobox 828 35 67 2021-08-16T20:12:46Z wikipedia:ru>Putnik 0 scope="colgroup" для заголовков Scribunto text/plain local p = {}; local yesno = require('Module:Yesno') local function _renderLine( frame, args, i ) if args[ 'заголовок' .. i ] and args[ 'заголовок' .. i ] == '-' then return '' elseif args[ 'заголовок' .. i ] and args[ 'заголовок' .. i ] ~= '' then local style = ( args[ 'стиль_заголовков' ] or '' ) .. ( args[ 'стиль_заголовка' .. i ] or '' ); local class = ( args[ 'класс' .. i ] or '' ); return '\n<tr>\n<th colspan="2" scope="colgroup" class="infobox-header ' .. class .. '" style="' .. style .. '">' .. args[ 'заголовок' .. i ] .. '</th>\n</tr>'; end if args[ 'блок' .. i ] and args[ 'блок' .. i ] ~= '' then return args[ 'блок' .. i ]; end local text = args[ 'текст' .. i ] or ''; if args[ 'викиданные' .. i ] and args[ 'викиданные' .. i ] ~= '' then text = frame:expandTemplate{ title = 'Wikidata', args = { args[ 'викиданные' .. i ], text, from = args[ 'from' ] or '' } }; end if text ~= '' then local label = args[ 'метка' .. i ] or ''; local class = args[ 'класс' .. i ] or ''; if string.find(class, 'noplainlist') == nil and string.find(class, 'nofirstlevel') == nil then class = class .. ' plainlist'; end if class ~= '' then class = ' class="' .. class .. '"'; end local style = ( args[ 'стиль_текстов' ] or '' ) .. ( args[ 'стиль_текста' ] or '' ) .. ( args[ 'стиль_текста' .. i ] or '' ); if label == '' then style = 'text-align:center;' .. style; end if style ~= '' then style = ' style="' .. style .. '"'; end if label ~= '' then local labelClass = args[ 'класс_меток' ] or ''; if string.find(labelClass, 'noplainlist') == nil and string.find(labelClass, 'nofirstlevel') == nil then labelClass = labelClass .. ' plainlist'; end if labelClass ~= '' then labelClass = ' class="' .. labelClass .. '"'; end local labelStyle = ( args[ 'стиль_меток' ] or '' ) .. ( args[ 'стиль_метки' .. i ] or '' ); if labelStyle ~= '' then labelStyle = ' style="' .. labelStyle .. '"'; end return '\n<tr>\n<th scope="row"' .. labelClass .. labelStyle .. '>' .. label .. '</th>' .. '\n<td' .. class .. style .. '>\n' .. text .. '</td>\n</tr>'; end return '\n<tr>\n<td colspan="2"' .. class .. style .. '>\n' .. text .. '</td>\n</tr>'; end return ''; end local function maxNumber ( args ) local maxNumber = 0 for argName, _ in pairs(args) do local argNumber = mw.ustring.match(argName, '^[^0-9]+([0-9]+)$') if argNumber and tonumber(argNumber) > maxNumber then maxNumber = tonumber(argNumber) end end return maxNumber end function p.renderLine( frame ) local args = frame:getParent().args; return _renderLine(frame, args, '') end function p.renderLines( frame ) local args = frame:getParent().args; local res = '' local header, text = '', '' local autoHeaders = yesno(args [ 'автозаголовки' ] or 'false', false) for i = 1, maxNumber(args) do if args[ 'заголовок' .. i ] and args[ 'заголовок' .. i ] ~= '' then if text ~= '' or not autoHeaders then res = res .. header .. text end header, text = _renderLine(frame, args, i), '' else text = text .. _renderLine(frame, args, i) end end if text ~= '' or not autoHeaders then res = res .. header .. text end return res end return p; c830c997bd3d15923f347277e3b0ae71b7ba917e Модуль:Dates 828 61 119 2021-10-11T18:35:23Z wikipedia:ru>Wikisaurus 0 параметр nolinks для отключения викификации даты в [[Модуль:Wikidata/date]] Scribunto text/plain --[[ В это модуле собраны функции, связанные с работой с датами. ]] local monthg = {'января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', "сентября", "октября", "ноября", "декабря"} local monthd = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} local function DecodeDate(d)-- Ч, М, Г, СЧ, СМ, СГ, хвост --дата: "%-?%d+"=год, "%d+%.%d+"=число месяца, "%d+%.%d+%.%-?%d+"=ЧМГ, -- потом в скобках м.б. переопределено для старого стиля начиная с числа local nd=d:match("^[%d.-]*"); local od=d:match("^[%d.-]*%s*%(%s*([%d.-]*)%s*%)"); local tail = d:match("^[%d.-]+%s*%(%s*[%d.-]+%s*%)%s*(%S.*)") or d:match("^[%d.-]+%s*([^%s%d].*)"); if nd:match('^%-?%d+$' ) then return nil, nil, tonumber(nd), nil, nil, od and tonumber(od:match("%-?%d+$")),tail else local j,m,y=nd:match("^(%d+)%.(%d+)%.?(%-?%d*)"); if j then if od then local oj, om, oy = od:match("^(%d+)%.?(%d*)%.?(%-?%d*)"); return j and tonumber(j), m and tonumber(m), y>'' and tonumber(y) or nil, oj and tonumber(oj), om>'' and tonumber(om) or nil, oy>'' and tonumber(oy) or nil, tail end return j and tonumber(j), m and tonumber(m), y>'' and tonumber(y) or nil, nil, nil, nil, tail else return nil end end end local function Diffy(d1,m1,y1,d0,m0,y0)--аналог Персона/Дата/Прошло лет return y1-y0 - ( y1*y0<=0 and 1 or 0 ) - ( (m1<m0 or m1==m0 and d1<d0) and 1 or 0 ) end local function Year0(y,t)-- аналог Год0 if y>0 then return table.concat{ '[[', tostring(y), ' год|', t and tostring(y)..'&nbsp;'..t or tostring(y), ']]' } else return table.concat{ '[[', tostring(-y), ' год до н. э.|', t and tostring(-y)..'&nbsp;'..t or tostring(-y), '&nbsp;до&nbsp;н.&nbsp;э.]]' } end end local function FormDate(j,m,y,oj,om,oy,mo)-- ~ Персона/Дата/Logic 4 if j then if not m then return "''формат неверен''" end if y then return string.format( '<span class="nowrap">%s<span style="display:none">(<span class="%s">%04i-%02i-%02i</span>)</span></span>', table.concat( oj and ( om and ( oy and {-- ДД ММММ ГГГГ ([[ДД ММММ]] [[ГГГГ]]) oj,'&nbsp;',monthg[om],'&nbsp;',oy, '</span> <span class="nowrap">([[', j, ' ', monthg[m],']] ',Year0(y),')' } or {-- ДД ММММ ([[ДД ММММ]]) [[ГГГГ]] oj,'&nbsp;',monthg[om],' ([[',j,'&nbsp;',monthg[m],']]) ',Year0(y) } ) or {-- ДД [[ДД ММММ|(ДД) ММММ]] [[ГГГГ]] oj,'&nbsp;[[',j,' ',monthg[m],'|','(',j,')&nbsp;',monthg[m],']] ',Year0(y) } ) or {'[[',j,'&nbsp;',monthg[m],']]&nbsp;',Year0(y)} ),--/table.concat ({['Рождения']='bday',['Смерти']='dday'})[mo] or '', y,m,j )--/string.format else return '<span class="nowrap">' .. table.concat( oj and ( om and {-- ДД ММММ ([[ДД ММММ]]) oj,'&nbsp;',monthg[om],' ([[',j,'&nbsp;',monthg[m],']])</span>' } or {-- ДД [[ДД ММММ|(ДД) ММММ]] oj,'&nbsp;[[',j,' ',monthg[m],'|','(',j,')&nbsp;',monthg[m],']]</span>' } ) or {'[[',j,'&nbsp;',monthg[m],']]</span>'} ) end else return y and string.format( '<span class="nowrap">%s<span style="display:none;">(<span class="bday">%04i</span>)</span></span>', Year0(y,'год'),y) or "''формат неверен''" end end local function GetDate(D)--dd.mm.-?yyyy или -?yyyy-mm-dd в три переменных d,m,y local d,m,y = d:match('^%s*(%d%d?)[/.]([01]?%d)[/.](%-?%d+)') if not d then y,m,d = D:match('^%s*(%-?%d+)[-\\]0*(1?%d)[-\\]0*(%d+)') end return tonumber(d),tonumber(m),tonumber(y) end local function Cmp(a,b)--Сравнивает две даты, результат соответственно -1, 0 или 1 local d1,m1,y1 = GetDate(a) local d2,m2,y2 = GetDate(b) return d1 and d2 and (--nil, если формат не опознан y1==y2 and ( m1==m2 and ( d1==d2 and 0 or d1<d2 and -1 or 1 ) or m1<m2 and -1 or 1 ) or y1<y2 and -1 or 1 ) end local function Yyyymmdd(r)--Переводит русскую дату в YYYY,MM,DD local d, m, y, M = mw.ustring.match(r, "^%s*(%d%d?)%s+([а-яА-Я]+)%s+(%d+)") if not m then return nil end m = mw.ustring.lower(m) --тупо перебор for i = 1, 12 do if m == monthg[i] then M = i break end end if not M then return nil end return tonumber(y), M, tonumber(d) end local p = {} p = { ifdate=function(f)-- Для шаблона "Если дата", имитирует старое поведение -- Аргументы передаются шаблону return f:getParent().args[ mw.ustring.match(frame.args[1],"^[ %d.%-−%()]*$") and 2 or 3 ] end; DecodeDate = DecodeDate; Diffy = Diffy; Year0 = Year0; GetDate = GetDate; Cmp = Cmp; Yyyymmdd = Yyyymmdd; diffy = function(f)-- принимает параметры #invoke в виде двух строк-дат local d1,m1,y1=DecodeDate(f.args[1]); local d0,m0,y0=DecodeDate(f.args[2]) return Diffy(d1,m1,y1,d0,m0,y0) end; monthg=function(f) return monthg[ f.args[1] or f:getParent().args[1] ] end;--realmonth persdate=function(f)-- Для шаблона Персона/Дата;{{#invoke:dates|persdate|nocat={{NAMESPACE}}}} local frame=f:getParent(); local catpref,mo,d,d2={['Рождения']='Родившиеся',['Смерти']='Умершие'}, frame.args[1],frame.args[2],frame.args[3] local cat, j,m,y,oj,om,oy,tail, j2,m2,y2, age = '' if d then j,m,y,oj,om,oy,tail=DecodeDate(d:gsub('−','-')); if not (j or y) then return (frame.args.nocat and d or d..'[[Category:Википедия:Статьи с ручной викификацией дат в карточке]]') end end; if d2 then j2,m2,y2 = DecodeDate(d2:gsub('−','-')); end; return table.concat{ FormDate(j,m,y,oj,om,oy,mo), ( (frame.args['nopersoncat'] or '')~='' or (f.args['nocat'] or '')~='' ) and '' or table.concat{ '[[Category:Персоналии по алфавиту]]', j and string.format('[[Category:%s %i %s]]',catpref[mo],j,monthg[m]) or '', y and string.format('[[Category:%s в %s]]',catpref[mo],y,Year0(y,'году')) or '' },--/table.concat внутр. (function(F)--возраст if not F then return '' end; local n=F(); return n and string.format(" (%i %s)%s", n, mw.getLanguage('ru'):plural(n,'год','года','лет'), n>150 and '[[Category:Википедия:Статьи о персоналиях с большим текущим возрастом]]' or '' ) or '' end)( ({ ['Рождения']=function() local now=os.date('*t'); if (not d2 or d2=='') and j and m and y then return Diffy(now.day,now.month,now.year,j,m,y) end end, ['Смерти']=function() return j and m and y and j2 and m2 and y2 and Diffy(j,m,y,j2,m2,y2); end, })[mo] ),--конец вызова функции возраста tail or '', cat }--/table.concat внеш. end; formdate=function(f) -- Формирует дату по 3--6 параметрам #invoke или шаблона --не использовать с пустыми аргументами if (f.args[1] or '')~='' and (f.args[2] or '')~='' or (f.args[3] or '')~='' then return FormDate(f.args[1],f.args[2],f.args[3],f.args[4],f.args[5],f.args[6],f.args['m']) else local tf=f:getParent(); return FormDate(tf.args[1],tf.args[2],tf.args[3],tf.args[4],tf.args[5],tf.args[6],tf.args['m']) end end; cmp=function(f)--Сравнивает две даты, результат соответственно -1, 0 или 1 return Cmp(f.args[1],f.args[2]) end; G2J=function(f)--перевод григорианских дат в юлианские, возврат DD.MM.YYYY --Не знает про 15 октября 1582 года, не работает до нашей эры и после ???99 года --Если есть второй аргумент, преобразует только ДО этой даты включительно --Если есть третий аргумент, результат форматирует под Персона/Дата local d,m,y=GetDate(f.args[1]) if f.args[2] and Cmp(f.args[1],f.args[2])==1 then return string.format("%i.%i.%i",d,m,y) end local shift=math.floor(y/100)-math.floor(y/400)-2 if d-shift>0 then return f.args[3] and string.format("%i.%i.%i (%i)",d,m,y,d-shift) or string.format("%i.%i.%i",d-shift,m,y) else if m==1 then return f.args[3] and string.format("%i.1.%i (%i.12.%i)",d,y,31+d-shift,y-1) or string.format("%i.12.%i",31+d-shift,y-1) elseif m==3 then return f.args[3] and string.format("%i.3.%i (%i.2)", d,y, (y%4==0 and 29 or 28)+d-shift-(y%100==0 and y%400~=0 and 1 or 0) ) or string.format("%i.2.%i", (y%4==0 and 29 or 28)+d-shift-(y%100==0 and y%400~=0 and 1 or 0) ,y) else return f.args[3] and string.format( "%i.%i.%i (%i.%i)", d,m,y, monthd[m-1]+d-shift,m-1 ) or string.format("%i.%i.%i",monthd[m-1]+d-shift,m-1,y) end end end; -- Переводит русскую дату в YYYY-MM-DD. Возвращает входное значение, если дата уже в этом формате yyyymmdd = function(f) local date, hourmin = f.args[1] if mw.ustring.match(date, "^%s*%d+\-%d+\-%d+") then return date end hourmin = mw.ustring.match(date, "%s+%d+:%d+$") local y, m, d = Yyyymmdd(date) if not y then return '<span class="error">Ошибка: некорректный формат даты.</span>' end return string.format('%4i-%02i-%02i', y, m, d) .. (hourmin or '') end } function table.val_to_str ( v ) if "string" == type( v ) then v = string.gsub( v, "\n", "\\n" ) if string.match( string.gsub(v,"[^'\"]",""), '^"+$' ) then return "'" .. v .. "'" end return '"' .. string.gsub(v,'"', '\\"' ) .. '"' else return "table" == type( v ) and table.tostring( v ) or tostring( v ) end end function table.key_to_str ( k ) if "string" == type( k ) and string.match( k, "^[_%a][_%a%d]*$" ) then return k else return "[" .. table.val_to_str( k ) .. "]" end end function table.tostring( tbl ) local result, done = {}, {} for k, v in ipairs( tbl ) do table.insert( result, table.val_to_str( v ) ) done[ k ] = true end for k, v in pairs( tbl ) do if not done[ k ] then table.insert( result, table.key_to_str( k ) .. "=" .. table.val_to_str( v ) ) end end return "{" .. table.concat( result, "," ) .. "}" end local function parseISO8601Date(str) local pattern = "(%-?%d+)%-(%d+)%-(%d+)T" local Y, M, D = mw.ustring.match( str, pattern ) return tonumber(Y), tonumber(M), tonumber(D) end local function parseISO8601Time(str) local pattern = "T(%d+):(%d+):(%d+)%Z" local H, M, S = mw.ustring.match( str, pattern) return tonumber(H), tonumber(M), tonumber(S) end local function parseISO8601Offset(str) if str:sub(-1)=="Z" then return 0,0 end -- ends with Z, Zulu time -- matches ±hh:mm, ±hhmm or ±hh; else returns nils local pattern = "([-+])(%d%d):?(%d?%d?)$" local sign, oh, om = mw.ustring.match( str, pattern) sign, oh, om = sign or "+", oh or "00", om or "00" return tonumber(sign .. oh), tonumber(sign .. om) end function p.parseISO8601(str) if 'table'==type(str) then if str.args and str.args[1] then str = '' .. str.args[1] else return 'unknown argument type: ' .. type( str ) .. ': ' .. table.tostring( str ) end end local Y,M,D = parseISO8601Date(str) local h,m,s = parseISO8601Time(str) local oh,om = parseISO8601Offset(str) return tonumber(os.time({year=Y, month=M, day=D, hour=(h+oh), min=(m+om), sec=s})) end local g2uBoundary1 = p.parseISO8601('1582-10-15T00:00:00Z') local g2uBoundary2 = p.parseISO8601('1700-03-12T00:00:00Z') local g2uBoundary3 = p.parseISO8601('1800-03-13T00:00:00Z') local g2uBoundary4 = p.parseISO8601('1900-03-14T00:00:00Z') local g2uBoundary5 = p.parseISO8601('1918-01-26T00:00:00Z') -- декрет Ленина -- Передаваемое время обязано быть по Григорианскому календарю (новому стилю) function p.formatWiki( time, infocardClass, categoryNamePrefix ) if 'table'==type( time ) then if time.args and time.args[1] then time = tonumber( time.args[1] ) else return 'unknown argument type: ' .. type( time ) .. ': ' .. table.tostring( time ) end end local t = os.date("*t", time) if time < g2uBoundary1 then -- выводим просто юлианский календарь. Задавать тут григорианский некорректно return p.formatWikiImpl( t, t, infocardClass, categoryNamePrefix ) end -- Специальные даты if t.year == 1700 and t.month == 3 and t.day == 11 then return p.formatWikiImpl( {year=1700, month=2, day=29}, t, infocardClass, categoryNamePrefix) end if t.year == 1800 and t.month == 3 and t.day == 12 then return p.formatWikiImpl( {year=1800, month=2, day=29}, t, infocardClass, categoryNamePrefix ) end if t.year == 1900 and t.month == 3 and t.day == 13 then return p.formatWikiImpl( {year=1900, month=2, day=29}, t, infocardClass, categoryNamePrefix ) end if g2uBoundary1 <= time and time < g2uBoundary2 then return p.formatWikiImpl( os.date("*t", time - 10 * 24 * 60 * 60), t, infocardClass, categoryNamePrefix ) end if g2uBoundary2 <= time and time < g2uBoundary3 then return p.formatWikiImpl( os.date("*t", time - 11 * 24 * 60 * 60), t, infocardClass, categoryNamePrefix ) end if g2uBoundary3 <= time and time < g2uBoundary4 then return p.formatWikiImpl( os.date("*t", time - 12 * 24 * 60 * 60), t, infocardClass, categoryNamePrefix ) end if g2uBoundary4 <= time and time < g2uBoundary5 then return p.formatWikiImpl( os.date("*t", time - 13 * 24 * 60 * 60), t, infocardClass, categoryNamePrefix ) end --только Григорианский календарь return p.formatWikiImpl( t, t, infocardClass, categoryNamePrefix ) end local function ternary ( cond , T , F ) if cond then return T else return F end end local nominativeMonthes = {'январь', 'февраль', 'март', 'апрель', 'май', 'июнь', 'июль', 'август', 'сентябрь', 'октябрь', 'ноябрь', 'декабрь'} local genitivusMonthes = {'января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря'} local function nominativeYear( year, nolinks ) if ( year >= 0 ) then return nolinks and year or '[[' .. year .. ' год|' .. year .. ']]' else return nolinks and ( 0 - year ) .. ' до н. э.' or '[[' .. ( 0 - year ) .. ' год до н. э.|' .. ( 0 - year ) .. ' до н. э.]]' end end local function inYear( year ) if ( year >= 0 ) then return '' .. year .. ' году' else return '' .. ( 0 - year) .. ' году до н. э.' end end function p.formatWikiImpl( t1, t2, infocardClass, categoryNamePrefix, leftBracket, rightBracket, nolinks ) local nd = t2.day; local nm = t2.month; local ny = t2.year; local od = ternary ( t1.day ~= t2.day , t1.day, nil ); local om = ternary ( t1.month ~= t2.month , t1.month, nil ); local oy = ternary ( t1.year ~= t2.year , t1.year, nil ); if leftBracket == nil then leftBracket = '(' end if rightBracket == nil then rightBracket = ')' end local JulianComment = function(s) return tostring(mw.html.create("abbr") :attr("title","по юлианскому календарю") :wikitext(s) :done()) end local template = (nd ~= nil and "1" or "") .. (nm ~= nil and "2" or "") .. (ny ~= nil and "3" or "") .. (od ~= nil and "4" or "") .. (om ~= nil and "5" or "") .. (oy ~= nil and "6" or "") local datePart = '<span class="nowrap">' if (template == "12") then datePart = datePart .. string.format( nolinks and "%d %s" or "[[%d %s]]", nd, genitivusMonthes[nm] ) elseif (template == "23") then datePart = datePart .. string.format( "%s %s", nominativeMonthes[nm], nominativeYear( ny, nolinks ) ) elseif (template == "3") then datePart = datePart .. nominativeYear( ny, nolinks ) elseif (template == "123") then datePart = datePart .. string.format( nolinks and "%d %s %s" or "[[%d %s]] %s", nd, genitivusMonthes[nm], nominativeYear( ny, nolinks ) ) elseif (template == "124") then if nolinks then datePart = datePart .. JulianComment(string.format( "%d", od ) ).. string.format( " " .. leftBracket .. "%d" .. rightBracket .. " %s", nd, genitivusMonthes[nm] ) else datePart = datePart .. JulianComment(string.format( "%d", od ) ).. string.format( " [[%d %s|" .. leftBracket .. "%d" .. rightBracket .. " %s]]", nd, genitivusMonthes[nm], nd, genitivusMonthes[nm] ) end elseif (template == "1234") then if nolinks then datePart = datePart .. JulianComment(string.format( "%d", od ) ).. string.format( " |" .. leftBracket .. "%d" .. rightBracket .. " %s %s", nd, genitivusMonthes[nm], nominativeYear( ny, nolinks ) ) else datePart = datePart .. JulianComment(string.format( "%d", od ) ).. string.format( " [[%d %s|" .. leftBracket .. "%d" .. rightBracket .. " %s]] %s", nd, genitivusMonthes[nm], nd, genitivusMonthes[nm], nominativeYear( ny, nolinks ) ) end elseif (template == "1245") then datePart = datePart .. JulianComment(string.format( "%d %s", od, genitivusMonthes[om] ) ).. string.format(" " .. leftBracket .. (nolinks and "%d %s" or "[[%d %s]]") .. rightBracket .. "", nd, genitivusMonthes[nm] ) elseif (template == "12345") then datePart = datePart .. JulianComment(string.format( "%d %s", od, genitivusMonthes[om] ) ).. string.format(" " .. leftBracket .. (nolinks and "%d %s" or "[[%d %s]]") .. rightBracket .. " %s", nd, genitivusMonthes[nm], nominativeYear( ny, nolinks ) ) elseif (template == "123456") then datePart = datePart .. JulianComment(string.format( "%d %s %d", od, genitivusMonthes[om], oy )) .. '</span> <span class="nowrap">' .. string.format(" " .. leftBracket .. (nolinks and "%d %s %s" or "[[%d %s]] %s") .. rightBracket , nd, genitivusMonthes[nm], nominativeYear( ny, nolinks ) ) else datePart = datePart .. 'формат неверен' end datePart = datePart .. '</span>' local infocardTemplate = (nd ~= nil and "1" or "") .. (nm ~= nil and "2" or "") .. (ny ~= nil and "3" or "") if infocardClass then if (infocardTemplate == "123") then datePart = datePart .. string.format('<span style="display:none">(<span class="%s">%04d-%02d-%02d</span>)</span>', infocardClass , ny , nm , nd ) elseif (infocardTemplate == "23") then datePart = datePart .. string.format('<span style="display:none">(<span class="%s">%04d-%02d</span>)</span>', infocardClass , ny , nm ) elseif (infocardTemplate == "3") then datePart = datePart .. string.format('<span style="display:none;">(<span class="%s">%04d</span>)</span>', infocardClass , ny ) end end if categoryNamePrefix then if ( nd ~= nil and nm ~= nil) then datePart = datePart .. '[[Category:' .. categoryNamePrefix .. ' ' .. nd .. ' ' .. genitivusMonthes[nm] .. ']]' end if ( ny ~= nil) then datePart = datePart .. '[[Category:' .. categoryNamePrefix .. ' в ' .. inYear( ny ) .. ']]' end end return datePart end return p 902bb6a9ef5ce12ad4cfa19f3d2c964d7e092df7 Шаблон:Ombox 10 90 177 2021-10-24T18:05:30Z wikipedia:ru>Oleg Yunakov 0 Изменил настройки защиты для «[[Шаблон:Ombox]]»: критический шаблон или модуль: https://ru.wikipedia.org/w/index.php?title=Википедия:Установка_защиты&oldid=117401039#Шаблоны ([Редактирование=администраторы и инженеры] (бессрочно) [Переименование=администраторы и инженеры] (бессрочно)) wikitext text/x-wiki {{#invoke:Message box|ombox}}<noinclude> {{doc}}<!-- Add categories and interwikis to the /doc subpage, not here! --></noinclude> ab34435c5ebc29de589c9b059e88da5d0e6f16e4 Шаблон:Cl 10 92 181 2021-10-26T15:16:40Z wikipedia:ru>Jack who built the house 0 стилизация на основе [[Модуль:Template call code/styles.css]] wikitext text/x-wiki <templatestyles src="Модуль:Template call code/styles.css" />{{#if: {{{2|}}} | <span class="ts-templateCallCode-weak"><nowiki>[[</nowiki>Категория:[[:Категория:{{{1}}}|{{{1}}}]]<nowiki>]]</nowiki></span> | [[:Категория:{{{1}}}|{{{1}}}]] }}<noinclude>{{doc}}</noinclude> 3f315bb5453e2a3ef5f031e946f35c568b49f8b4 Модуль:Template call code 828 11 19 2021-10-26T19:03:06Z wikipedia:ru>Jack who built the house 0 -избыточный код Scribunto text/plain local getArgs = require('Module:Arguments').getArgs local ru = mw.language.new('ru') local p = {} -- Используется для того, чтобы можно было удалять элементы из таблицы local function copy(other) local res = {} for k, v in pairs(other) do res[k] = v end return res end local function makeInvokeFunc(funcName, flags) return function (frame) local args = copy(getArgs(frame, { trim = false, removeBlanks = false })) return p[funcName](args, flags) end end --предотвращает обработку вики-текста в отображении образца local function processText(str, nowiki) local res = str if nowiki then str = mw.text.unstripNoWiki(str) str = string.gsub(str, '%[', '&#91;') str = string.gsub(str, '%]', '&#93;') str = string.gsub(str, '<', '&lt;') str = string.gsub(str, '>', '&gt;') str = string.gsub(str, '{', '&#123;') str = string.gsub(str, '|', '&#124;') str = string.gsub(str, '}', '&#125;') str = string.gsub(str, '\'', '&#39;') str = string.gsub(str, '"', '&quot;') str = string.gsub(str, '(://)', '<span>%1</span>') end return str end local function addParams(args, params) local text, equals_pos, param, value = '', 0, '', '' local function addPipe() if params.spaced then text = text .. ' ' end text = text .. '<span class="' if not params.spaced then text = text .. ' ts-templateCallCode-pipe' end if not params.black then text = text .. ' ts-templateCallCode-weak' end -- &#124;, чтобы не трактовалось как разделитель ячеек в таблицах text = text .. '">&#124;</span>' end local beforeParam = '<span class="ts-templateCallCode-param">' local afterParam = '</span>' for k, v in pairs(args) do if type(k) == 'number' then -- Неименованные параметры if k >= params.from then equals_pos = v:find('=') if equals_pos and v:find('{{=}}') == equals_pos - 2 then equals_pos = nil end if equals_pos then -- Содержащие «=» преобразуем в именованные param = v:sub(1, equals_pos - 1) value = v:sub(equals_pos + 1) addPipe() text = text .. beforeParam .. processText(param, params.nowiki) .. '=' .. processText(value, params.nowiki) .. afterParam else -- Истинно неименованные addPipe() local paramValue = processText(v, params.nowiki) if #paramValue ~= 0 then text = text .. beforeParam .. paramValue .. afterParam end end end elseif not k:find('^_') then -- Именованные параметры, исключая модификаторы внешнего вида addPipe() text = text .. beforeParam .. processText(k, params.nowiki) .. '=' .. processText(v, params.nowiki) .. afterParam end end return text end function p._main(args, flags) local name = args[1] table.remove(args, 1) -- Вещи типа «=» в первом параметре if not name then for k, v in pairs(args) do if not k:find('^_') then name = k .. '=' .. v args[k] = nil break end end end local optpText if not flags.withoutParams then if name then local spanOffset = mw.ustring.find(name, '<span') -- След использования шаблона optp if spanOffset then optpText = mw.ustring.sub(name, spanOffset) name = mw.ustring.sub(name, 1, spanOffset - 1) end end end local yesno = require('Module:Yesno') local nolink, subst, podst, global, nav, noRedirect, ucFirst, black, nobr local tag, style, comment, lang, sister, global, textInPlaceOfName, namePrefix, prefix, postfix, nowiki local spaced, from if flags.withoutParams then for i, v in ipairs(args) do if v == 'nl' or v == 'nolink' then noLink = true elseif v == 's' then subst = true elseif v == 'п' then podst = true elseif v == 'g' then global = true elseif v == 'nav' then nav = true elseif v == 'noredir' then noRedirect = true elseif v == 'u' then ucFirst = true elseif v == 'b' then black = true elseif v == 'nobr' then nobr = true end end tag = args.tag or 'span' style = args.style comment = args.comment lang = args.lang sister = args.sister textInPlaceOfName = args.text namePrefix = args.nameprefix prefix = args.prefix postfix = args.postfix nowiki = args.nowiki else noLink = yesno(args._nolink or args._nl, false) or not yesno(args._link, false) subst = yesno(args._s, false) podst = yesno(args['_п'], false) global = yesno(args._g, false) nav = yesno(args._nav, false) noRedirect = yesno(args._noredir, false) ucFirst = yesno(args._u, false) black = yesno(args._b, false) nobr = yesno(args._nobr, false) tag = args._tag or 'span' style = args._style comment = args._comment lang = args._lang sister = args._sister textInPlaceOfName = args._text namePrefix = args._nameprefix prefix = args._prefix postfix = args._postfix nowiki = args._nowiki spaced = yesno(args._spaced, false) from = (tonumber(args._from) or 2) - 1 end global = global or name and mw.ustring.sub(name, 1, 1) == ':' black = black or tag ~= 'span' if textInPlaceOfName == '' then textInPlaceOfName = nil end if comment == '' then comment = nil end if lang == '' then lang = nil end if sister == '' then sister = nil end if namePrefix == '' then namePrefix = nil end if name then local trimmedName = mw.text.trim(name) if ru:lc(mw.ustring.sub(trimmedName, 1, 6)) == 'subst:' then subst = true name = mw.ustring.sub(trimmedName, 7) end if ru:lc(mw.ustring.sub(trimmedName, 1, 6)) == 'подст:' then podst = true name = mw.ustring.sub(trimmedName, 7) end end if subst then namePrefix = 'subst:' elseif podst then namePrefix = 'подст:' end local currentTitle = mw.title.getCurrentTitle() -- При опущенном первом параметре берём имя шаблона из названия страницы if name == '' or not name then local currentTitleRoot = currentTitle.rootText if not ucFirst and ( ( ru:uc(currentTitleRoot) ~= currentTitleRoot and -- Книга:Литературное наследство, TranslateDate not mw.ustring.match(currentTitleRoot, '^[А-Яа-яA-Za-z]+:?[А-ЯA-Z]') ) or #currentTitleRoot == 1 ) then name = ru:lcfirst(currentTitleRoot) else name = currentTitleRoot end end -- Начинаем собирать код local linkBody, titleObject, linkBegin, linkDivider, linkEnd local prefixes = {} if lang then table.insert(prefixes, lang) end if sister then table.insert(prefixes, sister) end linkBody = table.concat(prefixes, ':') if #linkBody ~= 0 then linkBody = ':' .. linkBody end if mw.ustring.sub(name, 1, 1) ~= ':' then linkBody = linkBody .. ':' end if not global then linkBody = linkBody .. 'Template:' end linkBody = linkBody .. name titleObject = mw.title.new(linkBody) local noLink = noLink or currentTitle == titleObject if not noLink then if not noRedirect or ( noRedirect and not lang and not sister and not titleObject.exists ) then linkBegin = '[[' linkEnd = ']]' linkDivider = '|' else linkBegin = '[' linkEnd = ']' linkDivider = ' ' linkBody = titleObject:fullUrl('redirect=no') end end local text = '' if tag then text = text .. '<' .. tag .. ' class="ts-templateCallCode' if nobr then text = text .. ' nowrap' end text = text .. '"' if style then text = text .. ' style="' .. style .. '"' end text = text .. '>' end if prefix then text = text .. processText(prefix, nowiki) end text = text .. '<span class="' if not spaced then text = text .. ' ts-templateCallCode-opening' end if not black then text = text .. ' ts-templateCallCode-weak' end text = text .. '">{{' if namePrefix then text = text .. namePrefix end text = text .. '</span>' if nav and currentTitle == titleObject then text = text .. '\'\'\'' end text = text .. '<span class="ts-templateCallCode-templateName" data-navboxnavigation-link="0">' local commentedLabel if comment then -- https://phabricator.wikimedia.org/T200704 -- commentedLabel = mw.getCurrentFrame():expandTemplate({title = 'comment', args = {(textInPlaceOfName or name), comment}}) commentedLabel = '<span class="commentedText" title="' .. comment .. '" style="border-bottom: 1px dotted; cursor: help;">' .. (textInPlaceOfName or name) .. '</span>' end local label = (commentedLabel or textInPlaceOfName or name) if not noLink then if noRedirect then text = text .. '<span class="plainlinks">' end text = text .. linkBegin .. linkBody .. linkDivider .. label .. linkEnd if noRedirect then text = text .. '</span>' end else text = text .. label end text = text .. '</span>' if nav and currentTitle == titleObject then text = text .. '\'\'\'' end if not flags.withoutParams then if optpText then text = text .. optpText end text = text .. addParams(args, { spaced = spaced, black = black, nowiki = nowiki, from = from }) if spaced then text = text .. ' ' end end text = text .. '<span class="' if not spaced then text = text .. ' ts-templateCallCode-closing' end if not black then text = text .. ' ts-templateCallCode-weak' end text = text .. '">}}</span>' if postfix then text = text .. processText(postfix, nowiki) end if tag then text = text .. '</' .. tag .. '>' end local ts = mw.getCurrentFrame():extensionTag{ name = 'templatestyles', args = { src = 'Модуль:Template call code/styles.css' } } return ts .. text end function p._onlyParams(args) local yesno = require('Module:Yesno') return addParams(args, { spaced = yesno(args._spaced, false), black = true, nowiki = yesno(args._nowiki, false), from = 1 }) end p.withoutParams = makeInvokeFunc('_main', {withoutParams = true}) p.withParams = makeInvokeFunc('_main', {withoutParams = false}) p.onlyParams = makeInvokeFunc('_onlyParams') return p c4cde66869b509219e9bf629a766ce30ad0bdf97 Шаблон:C 10 96 189 2021-11-05T11:44:04Z wikipedia:ru>GAndy 0 Изменил настройки защиты для «[[Шаблон:C]]»: понижение защиты согласно количеству включений (больше 2000, меньше 5000) ([Редактирование=только автоподтверждённые] (бессрочно) [Переименование=только автоподтверждённые] (бессрочно)) wikitext text/x-wiki {{#switch: {{{2}}} | Р = {{{к|к}}}атегории | Д = {{{к|к}}}атегории | В = {{{к|к}}}атегорию | Т = {{{к|к}}}атегорией | П = {{{к|к}}}атегории | ю = {{{к|к}}}атегорию | ей | й = {{{к|к}}}атегорией | и = {{{к|к}}}атегории | {{{к|к}}}атегория }} «[[:Категория:{{{1}}}|{{вложенные кавычки|{{{1}}}}}]]»<noinclude>{{doc}}</noinclude> 29dc241d0737db87ea05ae164b21b3bdc0da3f83 Модуль:Template call code/styles.css 828 13 23 2021-11-15T10:35:51Z wikipedia:ru>Jack who built the house 0 поддержка [[t:optp]] (например, на [[Модуль:Unsubst/doc]]) text text/plain .ts-templateCallCode-weak { color: #72777d; } .ts-templateCallCode-pipe { margin: 0 2px; } .ts-templateCallCode-pipe + .ts-templateCallCode-pipe, /* Template:Optp */ .ts-templateCallCode-pipe + .ts-templateCallCode-param > .ts-templateCallCode-weak:first-child > .ts-templateCallCode-pipe:first-child { margin-left: 0; } .ts-templateCallCode-param + .ts-templateCallCode-closing { margin-left: 2px; } span.ts-templateCallCode > .ts-templateCallCode-templateName a { /* Решение из https://ru.wikipedia.org/wiki/Шаблон:Фиттс */ padding: 0 0.5em !important; /* Перезаписываем стиль для .plainlinks a.external */ position: relative; margin: -0.5em; } /* [[Категория:Шаблоны:Подстраницы CSS]] */ b3ed166240cf28c48a58b8d992794b753b2c6ef5 Шаблон:Lang-en 10 62 121 2022-01-02T12:52:08Z wikipedia:ru>Abiyoyo 0 замена редиректа прямым включением wikitext text/x-wiki <nowiki />[[английский язык|англ.]]&nbsp;{{lang-en2|{{{1}}}}}<noinclude> {{doc|Lang/doc}} </noinclude> 6fcc1d4dc63f133033671bf27e48a6e701e126cb Шаблон:Карточка 10 24 45 2022-04-03T23:49:38Z wikipedia:ru>Putnik 0 пробуем красить каждую карточку на странице отдельно, без перекрытия стилей; надеюсь, комбинация имя+вверху0+вверху+вверху2 достаточно уникальна и не вызовет ошибок wikitext text/x-wiki {{#if:{{{имя|}}}|{{#ifeq:{{{имя|}}}|-||{{#if:{{{цвет|}}}|{{#tag:templatestyles| |wrapper=.infobox-{{#invoke:Hash|main|{{{имя}}} {{{вверху0|}}} {{{вверху|}}} {{{вверху2|}}}}} |src=Шаблон:Цвет/{{{цвет|}}}.css }}}}}}}}<table class="infobox infobox-{{#invoke:Hash|main|{{{имя}}} {{{вверху0|}}} {{{вверху|}}} {{{вверху2|}}}}} {{{класс_тела|}}}" style="{{{стиль_тела|}}}" {{#if:{{{имя|}}}|{{#ifeq:{{{имя|}}}|-||data-name="{{{имя}}}"}}}} {{#if:{{{from|}}}|{{#ifeq:{{{from|}}}|-||data-from="{{{from}}}"}}}}><!-- Вверху0 -->{{#if:{{{вверху0|}}}|<tr><td colspan="2" class="{{{класс_вверху0|}}}" style="text-align:center; {{{стиль_вверху0|}}}">{{{вверху0}}}</td></tr>}}<!-- Вверху -->{{#if:{{{вверху|}}}|<tr><th colspan="2" scope="colgroup" class="infobox-above {{{класс_вверху|}}}" style="{{{стиль_вверху|}}}">{{{вверху}}}</th></tr>}}<!-- Вверху2 -->{{#if:{{{вверху2|}}}|<tr><td colspan="2" class="{{{класс_вверху2|}}}" style="text-align:center; {{{стиль_вверху2|}}}">{{{вверху2}}}</td></tr>}}<!-- Вверху3 -->{{#if:{{{вверху3|}}}|<tr><td colspan="2" class="{{{класс_вверху3|}}}" style="text-align:center; {{{стиль_вверху3|}}}">{{{вверху3}}}</td></tr>}}<!-- Изображение -->{{#if:{{{изображение|}}}|<tr><td colspan="2" class="infobox-image {{{класс_изображения|}}}" style="{{{стиль_изображения|}}}"> {{{изображение}}} {{#if:{{{подпись|}}}| <div class="media-caption" style="{{{стиль_подписи|}}}">{{{подпись}}}</div>}}</td></tr>}}<!-- Изображение2 -->{{#if:{{{изображение2|}}}|<tr><td colspan="2" class="infobox-image {{{класс_изображения2|}}}" style="{{{стиль_изображения2|}}}"> {{{изображение2}}} {{#if:{{{подпись2|}}}| <div class="media-caption" style="{{{стиль_подписи2|}}}">{{{подпись2}}}</div>}}</td></tr>}}<!-- Изображение3 -->{{#if:{{{изображение3|}}}|<tr><td colspan="2" class="infobox-image {{{класс_изображения3|}}}" style="{{{стиль_изображения3|}}}"> {{{изображение3}}} {{#if:{{{подпись3|}}}| <div class="media-caption" style="{{{стиль_подписи3|}}}">{{{подпись3}}}</div>}}</td></tr>}}<!-- Строки -->{{#invoke:Infobox|renderLines}}<!-- Внизу -->{{Карточка/внизу| стиль_внизу_общий={{{стиль_внизу|}}}| класс_внизу={{{класс_внизу|}}}| внизу={{{внизу|}}}}}<!-- Внизу N -->{{#invoke:Transclude|npc|Карточка/внизу| стиль_внизу_общий={{{стиль_внизу|}}}| стиль_внизу=| класс_внизу=| внизу=}} </table><includeonly><!-- статьи -->{{#if:{{NAMESPACE}}||<!-- -->{{#if:{{{имя|}}}||[[Категория:Статьи с шаблонами-карточками без имени]]}}<!-- -->{{#ifeq:{{{имя|}}}|{{subst:PAGENAME}}|[[Категория:Статьи с шаблонами-карточками без имени]]}}<!-- -->}}<!-- шаблоны -->{{#ifeq:{{NAMESPACENUMBER}}|10|<!-- -->{{#if:{{{имя|}}}||[[Категория:Шаблоны-карточки без имени]]}}<!-- -->{{#ifeq:{{{имя|}}}|{{subst:PAGENAME}}|[[Категория:Шаблоны-карточки без имени]]}}<!-- -->{{#if:{{{название|}}}{{{стиль_названия|}}}|[[Категория:Шаблоны с использованием параметра «название» в шаблоне «Карточка»]]}}<!-- -->{{#if:{{{подпись|}}}{{{стиль_подписи|}}}{{{подпись2|}}}{{{стиль_подписи2|}}}{{{подпись3|}}}{{{стиль_подписи3|}}}|[[Категория:Шаблоны с использованием параметра «подпись» в шаблоне «Карточка»]]}}<!-- -->{{#ifexpr:{{#invoke:Color_contrast|styleratio|{{{стиль_тела|}}}}} < 4.5|[[Категория:Потенциально нечитаемые карточки]]}}<!-- -->{{#ifexpr:{{#invoke:Color_contrast|styleratio|{{{стиль_названия|}}}}} < 4.5|[[Категория:Потенциально нечитаемые карточки]]}}<!-- -->{{#ifexpr:{{#invoke:Color_contrast|styleratio|{{{стиль_вверху|}}}}} < 4.5|[[Категория:Потенциально нечитаемые карточки]]}}<!-- -->{{#ifexpr:{{#invoke:Color_contrast|styleratio|{{{стиль_вверху2|}}}}} < 4.5|[[Категория:Потенциально нечитаемые карточки]]}}<!-- -->{{#ifexpr:{{#invoke:Color_contrast|styleratio|{{{стиль_вверху3|}}}}} < 4.5|[[Категория:Потенциально нечитаемые карточки]]}}<!-- -->{{#ifexpr:{{#invoke:Color_contrast|styleratio|{{{стиль_подписи|}}}}} < 4.5|[[Категория:Потенциально нечитаемые карточки]]}}<!-- -->{{#ifexpr:{{#invoke:Color_contrast|styleratio|{{{стиль_подписи2|}}}}} < 4.5|[[Категория:Потенциально нечитаемые карточки]]}}<!-- -->{{#ifexpr:{{#invoke:Color_contrast|styleratio|{{{стиль_подписи3|}}}}} < 4.5|[[Категория:Потенциально нечитаемые карточки]]}}<!-- -->{{#ifexpr:{{#invoke:Color_contrast|styleratio|{{{стиль_заголовков|}}}}} < 4.5|[[Категория:Потенциально нечитаемые карточки]]}}<!-- -->{{#ifexpr:{{#invoke:Color_contrast|styleratio|{{{стиль_меток|}}}}} < 4.5|[[Категория:Потенциально нечитаемые карточки]]}}<!-- -->{{#ifexpr:{{#invoke:Color_contrast|styleratio|{{{стиль_текста|}}}}} < 4.5|[[Категория:Потенциально нечитаемые карточки]]}}<!-- -->{{#ifexpr:{{#invoke:Color_contrast|styleratio|{{{стиль_внизу|}}}}} < 4.5|[[Категория:Потенциально нечитаемые карточки]]}}<!-- -->{{#ifeq:{{{имя|}}}|{{PAGENAME}}|<!-- -->[[Категория:Шаблоны-карточки по алфавиту|{{ucfirst:{{без начала|{{PAGENAME}}|Карточка }}}}]]<!-- -->{{#if:{{{стиль_тела|}}}{{{стиль_вверху|}}}{{{стиль_заголовков|}}}{{{стиль_внизу|}}}|[[Категория:Википедия:Шаблоны-карточки с явным указанием стилей]]}}<!-- -->}}<!-- -->}}<!-- любое пространство имён -->{{#if:{{{название|}}}{{{стиль_названия|}}}|[[Категория:Википедия:Страницы с использованием параметра «название» в шаблоне «Карточка»]]}}<!-- -->{{#if:{{{подпись|}}}{{{стиль_подписи|}}}{{{подпись2|}}}{{{стиль_подписи2|}}}{{{подпись3|}}}{{{стиль_подписи3|}}}|[[Категория:Википедия:Страницы с использованием параметра «подпись» в шаблоне «Карточка»]]}}</includeonly><noinclude>{{doc}}</noinclude> 5bd0cadc0cad51dc109de7db63622ab36743d386 Шаблон:Карточка/Викисклад 10 27 51 2022-04-30T14:39:04Z wikipedia:ru>ShinePhantom 0 еще одна проверочная категория для зачистки wikitext text/x-wiki {{wikidata|p373|{{str rep|{{str rep|{{{1|}}}|Category:|}}|category:|}}|plain=false|text=Медиафайлы на Викискладе|icon={{{icon|}}}|icon_size={{{icon_size|}}}|from={{{from|}}}}}<!-- -->{{#if: {{{nocat|}}}{{NAMESPACE}} || <!-- -->{{#if: {{{1|}}} | [[Категория:Википедия:Ссылка на Викисклад непосредственно в статье]]<!-- -->{{#if: {{wikidata|p373|plain=true}} | {{#ifeq: {{str rep|{{str rep|{{{1|}}}|Category:|}}|category:|}} | {{wikidata|p373|plain=true}} |[[Категория:Википедия:Ссылки на Викисклад в статье и на Викиданных совпадают]]| [[Категория:Википедия:Ссылки на Викисклад в статье и на Викиданных отличаются]] }} | [[Категория:Википедия:Ссылка на Викисклад в статье, но не на Викиданных]] }} }}<!-- --> }}<!-- -->{{#ifeq: {{NAMESPACE}} | Шаблон | {{#if: {{{2|}}} | [[Категория:Википедия:Шаблоны для низа карточек с лишним параметром]] }} }}<!-- --><noinclude> {{doc}} </noinclude> 40ef9a463c772ddbf54feae9e21d4037b692253e Шаблон:Флагификация/Германия 10 70 137 2022-10-16T05:50:42Z wikipedia:ru>Well-Informed Optimist 0 уточнение wikitext text/x-wiki {{ {{{1<noinclude>|флагификация/флаг</noinclude>}}} | alias = Германия | flag alias = Flag of Germany.svg | flag alias-империя = Flag of the German Empire.svg | flag alias-1871 = Flag of the German Empire.svg | flag alias-1919 = Flag of Germany (2-3).svg | flag alias-1933-1 = National flag of Germany 1933-1935.svg | flag alias-1933 = Flag of German Reich (1935–1945).svg | flag alias-1946 = Flag of Germany (1946-1949).svg | flag alias-Берлин = Flag of Berlin.svg | flag alias-ГДР = Flag of East Germany.svg | flag alias-1938 = War Ensign of Germany 1938-1945.svg | flag alias-ВМФ = Naval Ensign of Germany.svg | flag alias-1892 = Kaiserliche Kriegsflagge (1892).png | flag alias-1921 = War Ensign of Germany (1921–1933).svg | var1 = империя | var2 = 1871 | var3 = 1919 | var4 = 1933-1 | var5 = 1933 | var6 = 1946 | var7 = Берлин | var8 = ГДР | var9 = 1938 | var10 = ВМФ | var11 = 1892 | var12 = 1921 | variant = {{{variant|}}} | размер = {{{размер|}}} }} efa3b6861970635c792254f5da10e4efbc3ded5d Шаблон:Музыкант/цвет/схема 10 99 195 2023-04-27T01:30:31Z wikipedia:ru>Oleg Yunakov 0 Защитил страницу [[Шаблон:Музыкант/цвет/схема]]: критический шаблон или модуль: используется на 29 522 страницах ([Редактирование=администраторы и инженеры] (бессрочно) [Переименование=администраторы и инженеры] (бессрочно)) wikitext text/x-wiki <includeonly>{{#switch:{{lc:{{{1|}}}}}<!-- -->|solo_singer |вокалист=Вокалист<!-- -->|non_vocal_instrumentalist |инструменталист=Инструменталист<!-- -->|non_performing_personnel |композитор |продюсер |дирижёр=Композитор<!-- -->}}</includeonly><noinclude> {{doc}} </noinclude> 0fc69c91f5ef446372370b02ac2ddf786f06c3d5 Модуль:Wikidata/url 828 77 151 2023-05-09T00:51:03Z wikipedia:ru>Putnik 0 оптимизация потребления памяти за счёт замены mw.wikibase.getEntity() на mw.wikibase.getBestStatements() Scribunto text/plain local p = {} local function formatLangRefs( options ) local langRefs = {} if options.qualifiers and options.qualifiers.P407 then for _, qualifier in ipairs( options.qualifiers.P407 ) do if ( qualifier and qualifier.datavalue and qualifier.datavalue.type == 'wikibase-entityid' ) then local qualifierId = qualifier.datavalue.value.id local wbStatus, langRefCodeClaims = pcall( mw.wikibase.getBestStatements, qualifierId, 'P218' ) if wbStatus and langRefCodeClaims then for _, claim in ipairs( langRefCodeClaims ) do if ( claim.mainsnak and claim.mainsnak.datavalue and claim.mainsnak.datavalue.type == 'string' ) then local langRefCode = claim.mainsnak.datavalue.value table.insert( langRefs, options.frame:expandTemplate{ title = 'ref-' .. langRefCode } ) end end end end end end return table.concat( langRefs, '&#8203;' ) end function p.formatUrlValue( context, options, value ) local moduleUrl = require( 'Module:URL' ) local langRefs = formatLangRefs( options ) if not options.length or options.length == '' then options.length = math.max( 18, 25 - #langRefs ) end return moduleUrl.formatUrlSingle( context, options, value ) .. langRefs end return p 4a9959f45666b35899729e561a73e0535c16e15e Модуль:WikidataSelectors 828 33 63 2023-05-09T18:46:16Z wikipedia:ru>Putnik 0 исправление метода load() Scribunto text/plain local i18n = { ["errors"] = { ["rank-not-valid"] = "Некорретное значение приоритета (rank)", ["cant-parse-condition"] = "Не удалось разобрать условие" } } local validRanks = { 'best', 'preferred', 'normal', 'deprecated' } --[[ Internal function for error message Input: key in errors table Output: error message ]] local function throwError( key ) error( i18n.errors[key] ) end local p = {} --[[ Load property and filter statements Input: entityId, selector string Output: filtered statements table ]] function p.load( entityId, propertySelector ) local propertyId = mw.ustring.match( propertySelector, '^[Pp]%d+' ) if not propertyId then return nil end propertyId = string.upper( propertyId ) local allStatements = {} allStatements[ propertyId ] = mw.wikibase.getAllStatements( entityId, propertyId ) return p.filter( allStatements, propertySelector ) end --[[ Parse selectors and filter statements Input: statements table, selector string Output: filtered statements table ]] function p.filter( allClaims, propertySelector ) propertySelector = mw.text.trim( propertySelector ) -- Get property ID from selector local propertyId = mw.ustring.match( propertySelector, '^[Pp]%d+' ) if not propertyId then propertyId = '' end local initPos = #propertyId + 1 propertyId = string.upper( propertyId ) if ( not allClaims ) then return nil end local allPropertyClaims = allClaims[propertyId] if ( not allPropertyClaims ) then return nil end -- Gathering rules local rules = p.matchSelectors( propertySelector, initPos ) -- If there is no rank filter, than default rank is 'best' local isRanked = false for i, subRules in ipairs( rules ) do for j, rule in ipairs( subRules ) do if rule['type'] == 'rank' then isRanked = true break end end end if not isRanked then table.insert( rules, 1, { { type = 'rank', value = 'best' } } ) end -- Execute rules allPropertyClaims = p.applyRules( allPropertyClaims, rules ) return allPropertyClaims end --[[ Match and gather selector rules Input: string with selectors rules, start position Output: rules table ]] function p.matchSelectors( selectorsString, initPos ) local rules = {} local rawRulePattern = '^%s*%[%s*[^%[%]]+%s*%]%s*' local rulePattern = '^%s*%[%s*([^%[%]]+)%s*%]%s*$' if not initPos then initPos = 1 end local rawRule = mw.ustring.match( selectorsString, rawRulePattern, initPos ) while rawRule do initPos = initPos + #rawRule rule = mw.ustring.match( rawRule, rulePattern ) rule = mw.text.trim( rule ) local subRules = mw.text.split( rule, '%s*,%s*' ) local commands = {} local comm for i, subRule in ipairs( subRules ) do local isInversed = false if mw.ustring.match( subRule, '^!' ) then isInversed = true subRule = mw.ustring.match( subRule, '^!%s*(.+)$' ) end -- p123[1] if mw.ustring.match( subRule, '^%d+$' ) then table.insert( commands, { type = 'position', value = subRule, inversed = isInversed } ) -- p123[rank:preferred] elseif mw.ustring.match( subRule, '^rank%s*:%s*(%a+)$' ) then rank = mw.ustring.match( subRule, '^rank%s*:%s*(%a+)$' ) table.insert( commands, { type = 'rank', value = rank, inversed = isInversed } ) -- p123[language:xx] elseif mw.ustring.match( subRule, '^language%s*:%s*([%a%-]+)$' ) then value = mw.ustring.match( subRule, '^language%s*:%s*([%a%-]+)$' ) table.insert( commands, { type = 'language', value = value, inversed = isInversed } ) -- p123[language!:xx] elseif mw.ustring.match( subRule, '^language%s*!:%s*([%a%-]+)$' ) then value = mw.ustring.match( subRule, '^language%s*!:%s*([%a%-]+)$' ) table.insert( commands, { type = 'language', value = value, inversed = not isInversed } ) -- p123[min] elseif mw.ustring.match( subRule, '^min$' ) then table.insert( commands, { type = 'value_min' } ) -- p123[max] elseif mw.ustring.match( subRule, '^max$' ) then table.insert( commands, { type = 'value_max' } ) -- p123[min:p456] elseif mw.ustring.match( subRule, '^min%s*:%s*[Pp]%d+$' ) then value = mw.ustring.match( subRule, ':%s*([Pp]%d+)$' ) table.insert( commands, { type = 'qualifier_min', qualifier = value } ) -- p123[max:p456] elseif mw.ustring.match( subRule, '^max%s*:%s*[Pp]%d+$' ) then value = mw.ustring.match( subRule, ':%s*([Pp]%d+)$' ) table.insert( commands, { type = 'qualifier_max', qualifier = value } ) -- p123[unit:q789] elseif mw.ustring.match( subRule, '^unit%s*:%s*[^%[%],:]+$' ) then value = mw.ustring.match( subRule, ':%s*([^%[%],:]+)$' ) table.insert( commands, { type = 'unit', value = value, inversed = isInversed } ) -- p123[unit!:q789] elseif mw.ustring.match( subRule, '^unit%s*!:%s*[^%[%],:]+$' ) then value = mw.ustring.match( subRule, '!:%s*([^%[%],:]+)$' ) table.insert( commands, { type = 'unit', value = value, inversed = not isInversed } ) -- p123[p456] elseif mw.ustring.match( subRule, '^[Pp]%d+$' ) then qualifier = mw.ustring.match( subRule, '^[Pp]%d+' ) table.insert( commands, { type = 'qualifier', qualifier = qualifier, value = nil, inversed = isInversed } ) -- p123[p456:q789] elseif mw.ustring.match( subRule, '^[Pp]%d+%s*:%s*[^%[%],:]+$' ) then qualifier = mw.ustring.match( subRule, '^([Pp]%d+)%s*:?' ) value = mw.ustring.match( subRule, ':%s*([^%[%],:]+)$' ) table.insert( commands, { type = 'qualifier', qualifier = qualifier, value = value, inversed = isInversed } ) -- p123[p456!:q789] elseif mw.ustring.match( subRule, '^[Pp]%d+%s*!:%s*[^%[%],:]+$' ) then qualifier = mw.ustring.match( subRule, '^([Pp]%d+)%s*!:?' ) value = mw.ustring.match( subRule, '!:%s*([^%[%],:]+)$' ) table.insert( commands, { type = 'qualifier', qualifier = qualifier, value = value, inversed = not isInversed } ) -- p123[q456] elseif mw.ustring.match( subRule, '^[Qq]%d+$' ) then value = mw.ustring.match( subRule, '^[Qq]%d+' ) table.insert( commands, { type = 'value', value = value, inversed = isInversed } ) else throwError( 'cant-parse-condition' ) end end if #commands then table.insert( rules, commands ) end rawRule = mw.ustring.match( selectorsString, rawRulePattern, initPos ) end return rules end --[[ Intercept statements with selector rules Input: statements table, selector rules Output: filtered statements table ]] function p.applyRules( claims, rules ) for i, subRules in ipairs( rules ) do local newClaims = {} for j, rule in ipairs( subRules ) do if rule['type'] == 'rank' then table.insert( newClaims, p.filterByRank( claims, rule['value'], rule['inversed'] ) ) elseif rule['type'] == 'language' then table.insert( newClaims, p.filterByLanguage( claims, rule['value'], rule['inversed'] ) ) elseif rule['type'] == 'unit' then table.insert( newClaims, p.filterByUnit( claims, rule['value'], rule['inversed'] ) ) elseif rule['type'] == 'position' then table.insert( newClaims, p.filterByPosition( claims, rule['value'], rule['inversed'] ) ) elseif rule['type'] == 'qualifier' then table.insert( newClaims, p.filterByQualifier( claims, rule['qualifier'], rule['value'], rule['inversed'] ) ) elseif rule['type'] == 'qualifier_min' then table.insert( newClaims, p.filterUtterByQualifier( claims, rule['qualifier'], true ) ) elseif rule['type'] == 'qualifier_max' then table.insert( newClaims, p.filterUtterByQualifier( claims, rule['qualifier'], false ) ) elseif rule['type'] == 'value' then table.insert( newClaims, p.filterByValue( claims, rule['value'], rule['inversed'] ) ) elseif rule['type'] == 'value_min' then table.insert( newClaims, p.filterUtter( claims, true ) ) elseif rule['type'] == 'value_max' then table.insert( newClaims, p.filterUtter( claims, false ) ) end end claims = {} --[[ Merge all claims TODO: It's not good ]] for j, newSubClaims in ipairs( newClaims ) do for k, newClaim in ipairs( newSubClaims ) do local isNew = true for l, oldClaim in ipairs( claims ) do if oldClaim['id'] == newClaim['id'] then isNew = false break end end if isNew then table.insert( claims, newClaim ) end end end end return claims end --[[ Filter statements by rank Input: claims table, rank value, inversion Output: filtered statements table ]] function p.filterByRank( claims, rank, inversed ) if not inversed then inversed = false end if not rank then rank = 'best' end -- Check if rank value is valid local isValidRank = false for i, validRank in ipairs( validRanks ) do if rank == validRank then isValidRank = true break end end if not isValidRank then throwError( 'rank-not-valid' ) end -- Find the best rank if rank == 'best' then rank = 'normal' -- default rank (don't use deprecated even if it's no more claims) -- If we have at least one preferred rank, mark it as best for i, statement in pairs( claims ) do if (statement.rank == 'preferred') then rank = 'preferred' break end end end local resultClaims = {}; for i, statement in pairs( claims ) do if ( statement.rank == rank ) ~= inversed then table.insert( resultClaims, statement ) end end return resultClaims end --[[ Filter statements by language of value Input: claims table, language, inversion Output: filtered statements table ]] function p.filterByLanguage( claims, language, inversed ) if not inversed then inversed = false end local resultClaims = {} local mulStatement = {} for i, statement in ipairs( claims ) do isMatchLanguage = false if statement['mainsnak'] and statement['mainsnak']['datavalue'] and statement['mainsnak']['datavalue']['value'] and statement['mainsnak']['datavalue']['value']['language'] then if statement['mainsnak']['datavalue']['value']['language'] == language then isMatchLanguage = true end if statement['mainsnak']['datavalue']['value']['language'] == 'mul' then mulStatement = statement end end if isMatchLanguage ~= inversed then table.insert( resultClaims, statement ) end end if next(resultClaims) == nil and next(mulStatement) ~= nil then -- if specific language is not found, but there is Q20923490 value table.insert( resultClaims, mulStatement ) end return resultClaims end --[[ Filter statements by unit of value Input: claims table, unit, inversion Output: filtered statements table ]] function p.filterByUnit( claims, unit, inversed ) if not inversed then inversed = false end unit = 'http://www.wikidata.org/entity/' .. string.upper( unit ) local resultClaims = {} for i, statement in ipairs( claims ) do isMatchUnit = false if statement['mainsnak'] and statement['mainsnak']['datavalue'] and statement['mainsnak']['datavalue']['value'] and statement['mainsnak']['datavalue']['value']['unit'] and statement['mainsnak']['datavalue']['value']['unit'] == unit then isMatchUnit = true end if isMatchUnit ~= inversed then table.insert( resultClaims, statement ) break end end return resultClaims end --[[ Filter statements by position Input: claims table, position, inversion Output: filtered statements table ]] function p.filterByPosition( claims, position, inversed ) if not inversed then inversed = false end local resultClaims = {}; for statementPosition, statement in ipairs( claims ) do if ( statementPosition == tonumber( position ) ) ~= inversed then table.insert( resultClaims, statement ) break end end return resultClaims end --[[ Filter statements by qualifier existance or it's value Input: claims table, ID of qualifier's property, qualifier's value, inversion Output: filtered statements table ]] function p.filterByQualifier( claims, qualifierId, value, inversed ) if not inversed then inversed = false end qualifierId = string.upper( qualifierId ) local resultClaims = {} for i, statement in ipairs( claims ) do if statement['qualifiers'] and statement['qualifiers'][qualifierId] then if value == nil then if ( #statement['qualifiers'][qualifierId] > 0 ) ~= inversed then table.insert( resultClaims, statement ) end else local isQualifierFound = false for j, qualifier in ipairs( statement['qualifiers'][qualifierId] ) do if qualifier['datavalue'] then local qualifierValue = qualifier['datavalue']['value'] if qualifier['datavalue']['type'] == 'wikibase-entityid' then qualifierValue = qualifierValue.id value = string.upper( value ) end if qualifierValue == value then isQualifierFound = true break end end end if isQualifierFound ~= inversed then table.insert( resultClaims, statement ) end end elseif inversed then table.insert( resultClaims, statement ) end end return resultClaims end --[[ Filter statements by it's values Input: claims table, value, inversed Output: filtered statements table ]] function p.filterByValue( claims, value, inversed ) inversed = inversed or false local resultClaims = {} for i, statement in ipairs( claims ) do local statementValue if statement['mainsnak'] and statement['mainsnak']['datavalue'] and statement['mainsnak']['datavalue']['type'] then statementValue = statement['mainsnak']['datavalue']['value'] if statement['mainsnak']['datavalue']['type'] == 'quantity' then statementValue = statementValue.amount end if statement['mainsnak']['datavalue']['type'] == 'time' then statementValue = statementValue.time end if statement['mainsnak']['datavalue']['type'] == 'wikibase-entityid' then statementValue = statementValue.id value = string.upper( value ) end end if ( statementValue == value ) ~= inversed then table.insert( resultClaims, statement ) end end return resultClaims end --[[ Find a statement with minimum or maximum value Input: claims table, asc, inversed Output: filtered statements table ]] function p.filterUtter( claims, asc, inversed ) local resultValue = nil for i, statement in ipairs( claims ) do local statementValue if statement['mainsnak'] and statement['mainsnak']['datavalue'] and statement['mainsnak']['datavalue']['type'] then statementValue = statement['mainsnak']['datavalue']['value'] if statement['mainsnak']['datavalue']['type'] == 'quantity' then statementValue = statementValue.amount end if statement['mainsnak']['datavalue']['type'] == 'time' then statementValue = statementValue.time end if statement['mainsnak']['datavalue']['type'] == 'wikibase-entityid' then statementValue = statementValue.id end if not resultValue or ( statementValue < resultValue ) == asc then resultValue = statementValue end end end mw.logObject( resultValue, 'resultValue' ) return p.filterByValue( claims, resultValue, inversed ) end --[[ Find a statement with minimum or maximum qualifier value Input: claims table, qualifierId, asc Output: filtered statements table ]] function p.filterUtterByQualifier( claims, qualifierId, asc ) qualifierId = string.upper( qualifierId ) local resultValue = nil local resultStatement = nil for i, statement in ipairs( claims ) do if not statement['qualifiers'] and not statement['qualifiers'][qualifierId] then if resultStatement == nil then resultStatement = statement end else for _, qualifier in ipairs( statement['qualifiers'][qualifierId] ) do if qualifier['datavalue'] then local qualifierValue = qualifier['datavalue']['value'] if qualifier['datavalue']['type'] == 'quantity' then qualifierValue = qualifierValue.amount end if qualifier['datavalue']['type'] == 'time' then qualifierValue = qualifierValue.time end if qualifier['datavalue']['type'] == 'wikibase-entityid' then qualifierValue = qualifierValue.id end if not resultValue or ( qualifierValue < resultValue ) == asc then resultStatement = statement resultValue = qualifierValue end end end end end return { resultStatement } end return p 0bdff3a63bf171160cdec5c966211fbbf3003880 Модуль:Calendar 828 16 29 2023-05-17T17:44:45Z wikipedia:ru>Dima st bk 0 + короткие варианты для английского, см. [[Обсуждение шаблона:Cite web#Формат параметра %7Carchive-date=]] Scribunto text/plain local p = {} -- Необходимые модули и переменные local getArgs = require('Module:Arguments').getArgs local yesno = require('Module:Yesno') local mwlang = mw.getContentLanguage() local err = "―" -- NthDay nil result local tCon = table.concat -- 00) Блок многократно используемых списков local bool_to_number={ [true]=1, [false]=0 } local monthlang = {"января","февраля","марта","апреля","мая","июня","июля","августа","сентября","октября","ноября","декабря"} local month_to_num = {["января"]=1,["февраля"]=2,["марта"]=3,["апреля"]=4,["мая"]=5,["июня"]=6, ["июля"]=7,["августа"]=8,["сентября"]=9,["октября"]=10,["ноября"]=11,["декабря"]=12,["-"]=""} local monthd = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} local params = { {"г", "g"}, {"ю", "j"}} local comment = { '<span style="border-bottom: 1px dotted; cursor: help" title="по юлианскому календарю">','</span>'} -- duplicates: -- AST, BST, CST, ECT, IST, MST, PST, SST, local known_tzs = { ACDT='+10:30', ACST='+09:30', ACT ='+08:00', ADT ='-03:00', AEDT ='+11:00', AEST='+10:00', AFT ='+04:30', AKDT='-08:00', AKST ='-09:00', AMST ='+05:00', AMT ='+04:00', ART ='-03:00', AST ='+03:00', AST ='+04:00', AST ='+03:00', AST ='-04:00', AWDT='+09:00', AWST='+08:00', AZOST='-01:00', AZT ='+04:00', BDT ='+08:00', BIOT='+06:00', BIT ='-12:00', BOT ='-04:00', BRT ='-03:00', BST ='+06:00', BST ='+01:00', BTT ='+06:00', CAT ='+02:00', CCT ='+06:30', CDT ='-05:00', CEDT='+02:00', CEST='+02:00', CET ='+01:00', CHAST='+12:45', CIST='-08:00', CKT ='-10:00', CLST='-03:00', CLT ='-04:00', COST ='-04:00', COT ='-05:00', CST ='-06:00', CST ='+08:00', CVT ='-01:00', CXT ='+07:00', CHST='+10:00', DFT ='+01:00', EAST='-06:00', EAT ='+03:00', ECT ='-04:00', ECT ='-05:00', EDT ='-04:00', EEDT='+03:00', EEST ='+03:00', EET ='+02:00', EST ='-05:00', FJT ='+12:00', FKST='-03:00', FKT ='-04:00', GALT ='-06:00', GET ='+04:00', GFT ='-03:00', GILT='+12:00', GIT ='-09:00', GMT ='+00:00', GST ='-02:00', GYT ='-04:00', HADT='-09:00', HAST ='-10:00', HKT ='+08:00', HMT ='+05:00', HST ='-10:00', IRKT='+08:00', IRST ='+03:30', IST ='+05:30', IST ='+01:00', IST ='+02:00', JST ='+09:00', KRAT ='+07:00', KST ='+09:00', LHST='+10:30', LINT='+14:00', MAGT='+11:00', MDT ='-06:00', MIT ='-09:30', MSD ='+04:00', MSK ='+03:00', MST ='+08:00', MST ='-07:00', MST ='+06:30', MUT ='+04:00', NDT ='-02:30', NFT ='+11:30', NPT ='+05:45', NST ='-03:30', NT ='-03:30', OMST='+06:00', PDT ='-07:00', PETT ='+12:00', PHOT ='+13:00', PKT ='+05:00', PST ='-08:00', PST ='+08:00', RET ='+04:00', SAMT ='+04:00', SAST='+02:00', SBT ='+11:00', SCT ='+04:00', SLT ='+05:30', SST ='-11:00', SST ='+08:00', TAHT='-10:00', THA ='+07:00', UTC ='+00:00', UYST ='-02:00', UYT ='-03:00', VET ='-04:30', VLAT='+10:00', WAT ='+01:00', WEDT ='+01:00', WEST='+01:00', WET ='+00:00', YAKT='+09:00', YEKT ='+05:00', -- US Millitary (for RFC-822) Z='+00:00', A='-01:00', M='-12:00', N='+01:00', Y='+12:00', } local category = { ["no_parameters"]= "<!--[[Категория:Модуль:Calendar:Страницы без параметров]]-->", ["incomplete_parameters"]= "<!--[[Категория:Модуль:Calendar:Страницы с неполными или некорректными параметрами]]-->", ["without_verification"]= "<!--[[Категория:Модуль:Calendar:Страницы без проверки параметров]]-->", ["erroneous_parameters"]= "<!--[[Категория:Модуль:Calendar:Страницы с ошибочными параметрами]]-->" } -- несколько параметров передаются вместе с кодом ошибки в таблице, один может быть передан простым значением local e = { ["start"]="<span class=error>Ошибка: ", ["ending"]=".</span>", ["no_pattern_match"]="строка «%s» не совпадает с заданными паттернами", ["no_valid_date"]="дата «%s» не является корректной", ["wrong_jd"]="юлианская дата %s вне диапазона", ["no_data"]="нет входящих данных", ["too_many_arguments"]="ожидается менее %i аргументов", ["too_little_arguments"]="ожидается более %i аргументов", ["wrong_calculation"]="даты %s и %s не прошли проверку, %s дней разница", ["unknown_param"]="параметр %s неизвестен", ["unknown_error"]="неизвестная ошибка", ["tech_error"]="ошибка в функции %s", ["box_date"]="строка «%s» не является верной датой, пожалуйста, укажите дату в формате ГГГГ-ММ-ДД" -- [""]="", } local tzs_names = {"ACDT","ACST","ACT","ADT","AEDT","AEST","AFT","AKDT","AKST", "AMST","AMT","ART","AST","AST","AST","AST","AWDT","AWST","AZOST","AZT","BDT", "BIOT","BIT","BOT","BRT","BST","BST","BTT","CAT","CCT","CDT","CEDT","CEST", "CET","CHAST","CIST","CKT","CLST","CLT","COST","COT","CST","CST","CVT","CXT", "CHST","DFT","EAST","EAT","ECT","ECT","EDT","EEDT","EEST","EET","EST","FJT", "FKST","FKT","GALT","GET","GFT","GILT","GIT","GMT","GST","GYT","HADT","HAST", "HKT","HMT","HST","IRKT","IRST","IST","IST","IST","JST","KRAT","KST","LHST", "LINT","MAGT","MDT","MIT","MSD","MSK","MST","MST","MST","MUT","NDT","NFT", "NPT","NST","NT","OMST","PDT","PETT","PHOT","PKT","PST","PST","RET","SAMT", "SAST","SBT","SCT","SLT","SST","SST","TAHT","THA","UTC","UYST","UYT","VET", "VLAT","WAT","WEDT","WEST","WET","YAKT","YEKT","Z","A","M","N","Y","MSK"} local pattern = { -- для распознавания дат, переданных одним строчным параметром {"(-?%d%d%d%d?)[-%.%s/\\](%d%d)[-%.%s/\\](%d%d)", ["order"] = {3,2,1} }, -- yyyy mm dd {"(%d+)[-%.%s/\\](%d+)[-%.%s/\\](%d%d%d%d?)", ["order"] = {1,2,3} }, -- dd mm yyyy {"(%d%d)[-%.%s/\\](%d%d%d%d?)", ["order"] = {2,3} }, -- mm yyyy {"(%d%d%d%d?)[-%.%s/\\](%d%d)", ["order"] = {3,2} }, -- yyyy mm {"(%d+)%s(%l+)%s(%d%d%d%d?)", ["order"] = {1,2,3} }, -- d mmm y {"(%l+)%s(%d+),?%s(%d%d%d%d?)", ["order"] = {2,1,3} }, -- mmm d, y {"(%l+)%s(%d%d%d%d?)", ["order"] = {2,3} }, -- mmm y } local time_units = {"year","month","day"} --не используется --[[ local time_units = {"second", "minute", "hour", "day_of_month", "day_of_week", "day_of_year", "week", "month", "year", "year_of_century", "century"} ]]-- -- напоминание чтобы сделать более точные пересчёты - с часами / расчёт длительностей периодов local mnlang = {"ru_G", "ru_N", "en", "en_S", "de", "fr"} local month_lang = { ["ru_G"] = {"января","февраля","марта","апреля","мая","июня", "июля","августа","сентября","октября","ноября","декабря"}, ["ru_N"] = {"январь","февраль","март","апрель","май","июнь", "июль","август","сентябрь","октябрь","ноябрь","декабрь"}, ["en"] = {"january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december"}, ["en_S"] = {"jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"}, ["de"] = {"januar", "februar", "märz", "april", "mai", "juni", "juli", "august", "september", "oktober", "november", "dezember"}, ["fr"] = {"janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre"} } -- заполняется автоматически local reverse_month_lang = {} -- вспомогательная функция для обращения таблиц (смена ключей со значениями) local reverse_table = function (strait_table) local reversed_table = {} for k,v in pairs(strait_table) do reversed_table[v] = k end return reversed_table end -- запуск цикла по заполнению обратных таблиц, необходимых для распознавания дат local filling_months = function (mnlang, month_lang) for i=1, #mnlang do reverse_month_lang[mnlang[i]] = reverse_table(month_lang[mnlang[i]]) end end -- 10) Блок общих функций local function trim(str) if not str then return nil else return str:match'^()%s*$' and '' or str:match'^%s*(.*%S)' end end local function purif(str) if str == "" or str == nil then return nil elseif type(tonumber(str)) == "number" then return math.floor(tonumber(str)) else return nil end -- need .5 -- ,5 number format converter? end local function is(str) if (not str) or (str == "") then return false else return yesno(str,false) end end local function init(num) local output = {} for i=1,num do table.insert(output, {["year"]="", ["month"]="", ["day"]=""}) end return unpack(output) end local function isyear(tbl) if type(tbl) ~= 'table' then return false elseif not tbl["year"] then return false elseif type(tbl["year"]) == 'number' then return true else return false end end local function inbord(val, down, up) return not (type(up) ~= "number" or type(down) ~= "number" or type(val) ~= "number" or up < down or val < down or val > up) end local function shallowcopy(orig) local orig_type = type(orig) local copy if orig_type == 'table' then copy = {} for orig_key, orig_value in pairs(orig) do copy[orig_key] = orig_value end else -- number, string, boolean, etc copy = orig end return copy end local inlist = function ( var, list ) local n = #list local inlist = false for i=1,n do if var == list[i] then inlist = true end end return inlist end -- 20) Блок общих проверочных функций, связанных с датами local function unwarp(tbl) if not tbl then return "" elseif type(tbl) ~= "table" then return tbl elseif (tbl.day or tbl.month or tbl.year) then return (tbl.year or "?").."-"..(tbl.month or "?").."-"..(tbl.day or "?") else return (tbl[3] or "?").."-"..(tbl[2] or "?").."-"..(tbl[1] or "?") end end local function leap_year(y,jul) if (not y) or (type(y) ~= "number") then return false elseif (y % 4) ~= 0 then return false elseif not jul and (y % 100 == 0 and y % 400 ~= 0) then return false else return true end end -- функция для вычисления последнего дня месяца для юлианского и григорианского календарей local function month_end_day (month,year,is_julian) local month_end_day = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} -- если не задан год, дата 29 февраля считается допустимой if not month or type(month) ~= "number" or month < 1 or month > 12 then return nil elseif month ~= 2 or not year then return month_end_day[month] elseif month == 2 and (year % 4) == 0 and not ((not is_julian) and (year % 100 == 0 and year % 400 ~= 0)) then return 29 elseif month == 2 then return 28 else return nil -- в случае не целого значения входящих параметров или при иных непредусмотренных событиях end end local function isdate ( chain , jul ) -- можно использовать для проверки таблиц с полями day, month, year if not chain then return false elseif (not type(chain) == "table") or (not inbord(chain.year,-9999,9999)) or (not inbord(chain.month,1,12)) or (not inbord(chain.day,1,31)) or chain.day > monthd[chain.month] -- or chain.year == 0 then return false elseif chain.month == 2 and chain.day == 29 and not leap_year(chain.year,jul) then return false else return true end -- check for other calendars needed? end local function ispartdate ( chain ) if not chain then return false elseif not (type(chain) == "table") then return false elseif (inbord(chain.year,-9999,9999) or inbord(chain.month,1,12) or inbord(chain.day,1,31)) then return true else return false end -- partial date -- more detailed check for 31.02.0000 needed -- check for other calendars needed end -- from date1 to date2 in one year (beetwen jan-dec, dec-jan needed) local function partdist(date1,date2) local mont, dist = 0, 0 local d1d, d1m, d2d, d2m = (date1["day"] or ""), (date1["month"] or ""),(date2["day"] or ""), (date2["month"] or "") if not (inbord(d1d,1,31) and inbord(d2d,1,31)) then return false end -- нужна доп. проверка частичных дат на корректность if (inbord(d1m,1,12) or inbord(d2m,1,12)) and (d1m == "" or d2m == "") then mont = purif(date1["month"] or date2["month"]) d1m, d2m = mont, mont end -- mw.log("📏 day: " ..d1d .."->"..d2d.." month: ".. d1m.."->"..d2m ) if (inbord(d1m,1,12) and d1d <= monthd[d1m]) and (inbord(d2m,1,12) and d2d <= monthd[d2m]) then if d2m == d1m then dist = d2d - d1d else dist = monthd[d1m] - d1d + d2d end return dist else return math.huge end end local function dmdist(d1,d2) local p1,p2 = math.huge,math.huge if not not partdist(d1,d2) then p1=partdist(d1,d2) end if not not partdist(d2,d1) then p1=partdist(d2,d1) end -- if (not p1) or (not p2) then -- return (p1 or "") .. (p2 or "") -- else -- mw.log("d1, d2 = " .. undate(d1) .. ", " .. undate(d2)) return math.min(tonumber(partdist(d1,d2)) or math.huge,tonumber(partdist(d2,d1)) or math.huge) -- end end -- 30) Блок функций для обработки ввода-вывода дат local function undate(tbl) if not tbl then return "" else return (tbl.year or "").."-"..(tbl.month or "").."-"..(tbl.day or "") end end -- функция для нормализации значений дат и перевода месяцев в числа local function numerize(str) if type(str) == "number" then return math.floor(str) elseif str == "" or str == nil or type(str) ~= "string" then return nil elseif type(tonumber(str)) == "number" then return math.floor(tonumber(str)) else for i=1, #mnlang do if inlist(mw.ustring.lower(str),month_lang[mnlang[i]]) then return reverse_month_lang[mnlang[i]][mw.ustring.lower(str)] end end end end -- функция распознавания даты, переданной одной строкой local function parse_date(date_string) if type(date_string) ~= "string" or date_string == "" then return nil end local out_date_str = {"","",""} local error_data = {} for i=1, #pattern do local result_1, result_2, result_3 = mw.ustring.match(mw.ustring.lower(date_string),pattern[i][1]) if (result_1 or "") > "" then out_date_str[pattern[i].order[1]] = result_1 out_date_str[pattern[i].order[2]] = result_2 if (pattern[i].order[3]) then out_date_str[pattern[i].order[3]] = result_3 end -- mw.log("Паттерн " .. i .. ", строка: " .. date_string) break end end local date = { ["day"] =numerize(out_date_str[1]), ["month"]=numerize(out_date_str[2]), ["year"] =numerize(out_date_str[3])} return date --, error_data end ----[[ УСТАРЕЛО ]]---- local numstr2date = function(numstr) local format = "Y-m-d" local iso_date = mwlang:formatDate(format,numstr) local y,m,d = string.match(iso_date, "(%d+)-(%d+)-(%d+)") local dateout = {["year"]=purif(y), ["month"]=purif(m), ["day"]=purif(d)} return dateout end --local numstr2date = function(numstr) -- local nums = {} -- local dateout = {} -- for num in string.gmatch(numstr,"(%d+)") do -- table.insert(nums,purif(num)) -- end -- if #nums ~= 3 then error("В поле даты вместо трёх чисел с разделителями указано " .. #nums) -- elseif not inbord(nums[2],1,12) then error("Месяц с номером " .. nums[2] .. " не найден") -- elseif not inbord(nums[3],1,31) then -- dateout = {["year"]=nums[3], ["month"]=nums[2], ["day"]=nums[1]} -- elseif not inbord(nums[1],1,31) then -- dateout = {["year"]=nums[1], ["month"]=nums[2], ["day"]=nums[3]} -- elseif inbord(nums[1],1,31) then -- dateout = {["year"]=nums[3], ["month"]=nums[2], ["day"]=nums[1]} -- else -- local mwlang = mw.getContentLanguage() -- implement mwlang:formatDate(format,datein,true) here -- return error("Не распознано " .. numstr .. " как дата") -- end -- return dateout --end local function year2lang(numyear,yearmark,wiki) if not numyear then return "" end if not yearmark then yearmark = "" end local output = "" local bcmark = " до н. э." if numyear > 0 then bcmark = "" else numyear = 1 - numyear end if wiki then -- output = tCon({'[[', numyear,' год',bcmark,'|', numyear,']]', " ", yearmark, " ", bcmark}) output = tCon({'[[', numyear,' год',bcmark,'|', trim(numyear .. " " .. yearmark .. " " .. bcmark), ']]'}) else output = tCon({numyear, " ", yearmark, bcmark}) end return trim(output) end local function day2lang(datein,wikidate,wiki,inner_brt) -- if not isdate(wikidate) then wiki = false end if not ispartdate(datein) then return "" end local dm_separ, output = "", nil if (not (not datein.day)) and (not (not datein.month)) then dm_separ = " " end if (not datein.month) then datein.month = "" end if (not datein.day) then datein.day = "" end local monlan = monthlang[datein.month] or "" if wiki and not inner_brt then output = tCon({"[[", wikidate.day, " ", monthlang[wikidate.month] or "", "|", (datein.day or ""), dm_separ, monlan, "]]"}) elseif wiki then output = tCon({"[[", wikidate.day, " ", monthlang[wikidate.month] or "", "|", (datein.day or ""), dm_separ, monlan}) else output = tCon({datein.day, dm_separ, monlan}) end return trim(output) end local function triple_txt2date(d,m,y) -- добавить (args[1]:match("(%a+)") or "-") для нестандартной записи -- mw.ustring.match((m or ""),"(%a+)") local msg = "" local year = purif((y or "-"):match("(%d+)")) local month = purif(month_to_num[string.lower(mw.ustring.match((m or ""),"(%a+)"))]) local day = purif((d or "-"):match("(%d+)")) if not month then msg = category.incomplete_parameters month = purif(month_to_num[string.lower(mw.ustring.match((d or ""),"(%a+)") or "-")]) end if (not day) and ((purif(string.match(m or "","(%d+)") or "") or 32) <= (monthd[month] or 31)) then msg = category.incomplete_parameters day = purif(m:match("(%d+)") or "") end if not year then msg = category.incomplete_parameters year = purif(string.match(m or "","(%d+)") or "") end local dateout = {["year"]=year, ["month"]=month, ["day"]=day, ["msg"]=msg} return dateout end local function glue(d1,m1,y1,d2,m2,y2) if (not d1) and (not m1) and (not y1) and (not d2) and (not m2) and (not y2) then return category.incomplete_parameters end local gd,gm,gy,jd,jm,jy = (d1 or ""), (m1 or ""), (y1 or ""), (d2 or ""), (m2 or ""), (y2 or "") --mw.log(tCon({gd,gm,gy,jd,jm,jy})) local gm_sep = {" [["," год|","]]"} if (not gy) or (gy == "") then gm_sep = {"","",""} end return tCon({comment[1],trim(trim(jd .. " " .. jm) .. " " .. jy ), comment[2]," ([[",trim(gd .. " " .. gm),"]]",gm_sep[1],(gy:match("(%d+)") or ""), gm_sep[2],gy,gm_sep[3],")",category.incomplete_parameters}) end -- добавить отображение без года local function double_couple(jdate, gdate, wd, wm, wy, sq_brts, yearmark) local msg = "" msg = (jdate.msg or "") .. (gdate.msg or "") local cd = {} local jd = shallowcopy(jdate) local gd = shallowcopy(gdate) local left = "(" local right = ")" if sq_brts then left = "&#091;" right = "&#093;" end if (not isdate(jdate,true)) then return error((jdate.day or "") .. "." .. (jdate.month or "") .."." .. (jdate.year or "") .. " неподходящая дата") elseif (not isdate(gdate)) then return error((gdate.day or "") .. "." .. (gdate.month or "") .."." .. (gdate.year or "") .. " неподходящая дата") end if jd.year == gd.year then cd.year = gd.year gd.year, jd.year = nil, nil end if jd.month == gd.month then cd.month = gd.month gd.month, jd.month = nil, nil end if (not not cd.month) and wm then return tCon({comment[1] .. trim(day2lang(jd,jdate,false) .. " " .. year2lang(jd.year,yearmark,false)) .. comment[2], trim(left .. day2lang(gd,gdate,wd,wm) .. " " .. year2lang(gd.year,yearmark,wy)) .. right, day2lang(cd,gdate,false) .. "]]", trim(year2lang(cd.year,yearmark,wy)..msg)}, " ") end return tCon({comment[1] .. trim(day2lang(jd,jdate,false) .. " " .. year2lang(jd.year,yearmark,false)) .. comment[2], trim(left .. day2lang(gd,gdate,wd) .. " " .. year2lang(gd.year,yearmark,wy)) .. right, trim(day2lang(cd,gdate,false)), trim(year2lang(cd.year,yearmark,wy)..msg)}, " ") end -- 40) Блок функций для перевода дат с использованием [[Юлианская дата]] local function gri2jd( datein ) if not isdate(datein) then return error((datein.day or "") .. "." .. (datein.month or "") .."." .. (datein.year or "") .. " неподходящая дата") end local year = datein.year local month = datein.month local day = datein.day -- jd calculation local a = math.floor((14 - month)/12) local y = year + 4800 - a local m = month + 12*a - 3 local offset = math.floor(y/4) - math.floor(y/100) + math.floor(y/400) - 32045 local jd = day + math.floor((153*m + 2)/5) + 365*y + offset -- jd validation local low, high = -1931076.5, 5373557.49999 if not (low <= jd and jd <= high) then return error((datein.day or "") .. "." .. (datein.month or "") .. "." .. (datein.year or "") .. " выходит за пределы разрешённого диапазона") end return jd end local function jd2jul( jd ) if type(jd) ~= "number" then return error("Промежуточная переменная " .. (jd or "") .. " не является числом") end -- calendar date calculation local c = jd + 32082 local d = math.floor((4*c + 3)/1461) local e = c - math.floor(1461*d/4) local m = math.floor((5*e + 2)/153) local year_out = d - 4800 + math.floor(m/10) local month_out = m + 3 - 12*math.floor(m/10) local day_out = e - math.floor((153*m + 2)/5) + 1 -- output local dateout = {["year"]=year_out, ["month"]=month_out, ["day"]=day_out} return dateout end local function jul2jd( datein ) if not isdate(datein,true) then return error((datein.day or "") .. "." .. (datein.month or "") ..".".. (datein.year or "") .. " неподходящая дата") end local year = datein.year local month = datein.month local day = datein.day -- jd calculation local a = math.floor((14 - month)/12) local y = year + 4800 - a local m = month + 12*a - 3 local offset = math.floor(y/4) - 32083 local jd = day + math.floor((153*m + 2)/5) + 365*y + offset -- jd validation local low, high = -1930999.5, 5373484.49999 if not (low <= jd and jd <= high) then return error((datein.day or "") .. "." .. (datein.month or "") .."." .. (datein.year or "") .. " выходит за пределы разрешённого диапазона") end return jd end local function jd2gri( jd ) if type(jd) ~= "number" then return error("Промежуточная переменная " .. (jd or "") .. " не является числом") end -- calendar date calculation local a = jd + 32044 local b = math.floor((4*a + 3) / 146097) local c = a - math.floor(146097*b/4) local d = math.floor((4*c+3)/1461) local e = c - math.floor(1461*d/4) local m = math.floor((5*e+2)/153) local day_out = e - math.floor((153*m+2)/5)+1 local month_out = m + 3 - 12*math.floor(m/10) local year_out = 100*b + d - 4800 + math.floor(m/10) -- output local dateout = {["year"]=year_out, ["month"]=month_out, ["day"]=day_out} return dateout end local function astroyear(num, bc) if not num then return error() elseif type(num) ~= "number" then return error() end if num < 1 then return num end if not bc then return num else return 1 - num end end local function recalc(datein,calend) if inlist(calend,params[1]) then return jd2jul(gri2jd(datein)), datein elseif inlist(calend,params[2]) then return datein, jd2gri(jul2jd(datein)) else error("Параметр " .. (calend or "") .. " не опознан, разрешённые: " .. tCon(params[1]," ") .. " и " .. tCon(params[2]," ")) end end -- 50) Функции для обработки UTC local function utc(str,margin) local d = 1 local dchar = "+" local beginning = "[[UTC" local ending = "]]" local cat = "" local nums = {} local hmarg, timedec = 0, 0 local mmarg = "00" local output = "" -- checking type of input if not margin then margin = 0 elseif type(tonumber(margin)) ~= 'number' then output = "Can't shift by " .. margin error(output) end if type(str) ~= 'string' then error("Нет входящей строки") elseif str:byte(1) == 43 then elseif inbord(str:byte(1),48,57) then cat = "[[Категория:Википедия:Ошибка в часовом поясе НП]]" elseif str:byte(1) == 45 or string.sub(str,1,3) == "−" or string.sub(str,1,1)=="-" then d = -1 else error(string.char(str:byte(1)) .. " недопустимый первый символ") end -- parsing input for num in string.gmatch(str,"(%d+)") do table.insert(nums,purif(num)) end if #nums > 2 then error("Ожидается всего 2 числа, а не " .. #nums) elseif #nums == 0 then error("Необходимо что-то ввести") elseif #nums == 1 then if inbord(nums[1],0,14) then timedec = d*nums[1] + margin else error("Только часы от -14 до 14") end elseif #nums == 2 then if not inbord(nums[1],0,14) then error("Только часы от -14 до 14") elseif not inbord(nums[2],0,59) then error("Минуты только от 0 до 59") else timedec = d*(nums[1] + nums[2]/60) + margin end end if tonumber(timedec) == purif(timedec) then hmarg = timedec else local h, m = math.modf(math.abs(timedec)) hmarg = h mmarg = math.floor(m*60) end if timedec == 0 then dchar = "±" elseif timedec > 0 then elseif timedec < 0 then dchar = "&minus;" end -- output output = beginning .. dchar .. math.abs(hmarg) .. ":" .. string.format("%02d",mmarg) .. ending .. cat return output end -- 60) Блок функций ввода-вывода function p.NthDay( frame ) local args = getArgs(frame, { frameOnly = true }) local num, wday, mont, yea, format = purif(args[1]), purif(args[2]), purif(args[3]), purif(args[4]), args[5] if not format then format = "%d.%m.%y" end if not inbord(num,-5,5) then return error("The number must be between -5 and 5") elseif num == 0 then return error("The number must not be zero") end if not inbord(wday,0,6) then return error("The day of the week must be between 0 and 6") end if not inbord(mont,1,12) then return error("The month must be between 1 and 12") end if not inbord(yea,0,9999) then return error("Wrong year number") end if inbord(num,1,5) then local m_start = os.time{year=yea, month=mont, day=1, hour=0} local m_wds = tonumber(os.date("%w", m_start)) local start_shift = ( (num - bool_to_number[wday >= m_wds]) * 7 - (m_wds - wday) ) * 24 * 60 * 60 local tim = m_start + start_shift if tonumber(os.date("%m", tim)) == mont then return (os.date(format, tim)) else return (err) end elseif inbord(num,-5,-1) then local m_end = os.time{year = yea, month = mont + 1, day = 1, hour = 0} - 24 * 60 * 60 local m_wde = tonumber(os.date("%w", m_end)) local end_shift = ((math.abs(num + 1) + bool_to_number[wday > m_wde]) * 7 + (m_wde - wday)) * 24 * 60 * 60 local tim = m_end - end_shift if tonumber(os.date("%m", tim)) == mont then return (os.date(format, tim)) else return (err) end end end -- =p.ToIso(mw.getCurrentFrame():newChild{title="smth",args={"12 декабря 2020"}}) -- =p.ToIso(mw.getCurrentFrame():newChild{title="smth",args={"1.2.1602"}}) -- =p.ToIso(mw.getCurrentFrame():newChild{title="smth",args={"12.12.2021"}}) -- =p.ToIso(mw.getCurrentFrame():newChild{title="smth",args={"2021.12.12"}}) function p.ToIso( frame ) local args = getArgs(frame, { frameOnly = true }) local datein = args[1] -- инициализация, заполнение обратных таблиц, копирование параметров filling_months(mnlang, month_lang) -- парсинг входящей даты по шаблону local date = parse_date(datein) if not (type(date.year) == 'number') then return ("Wrong year: " .. unwarp(date)) end if not (1 <= date.month and date.month <= 12) then return ("Wrong month: " .. unwarp(date)) end if not date.day or not (1 <= date.day and date.day <= month_end_day(date.month,date.year)) then return ("Wrong day: " .. unwarp(date)) end local timedate = os.time{year=date.year, month=date.month, day=date.day} local date = os.date("%Y-%m-%d", timedate) return date end -- =p.BoxDate(mw.getCurrentFrame():newChild{title="smth",args={"12 декабря 2020"}}) -- =p.BoxDate(mw.getCurrentFrame():newChild{title="smth",args={"1.2.1602"}}) -- =p.BoxDate(mw.getCurrentFrame():newChild{title="smth",args={"декабрь 2020"}}) -- =p.BoxDate(mw.getCurrentFrame():newChild{title="smth",args={"12-2020"}}) -- =p.BoxDate(mw.getCurrentFrame():newChild{title="smth",args={"12.12.2021"}}) -- =p.BoxDate(mw.getCurrentFrame():newChild{title="smth",args={"2021.12.12"}}) -- =p.BoxDate(mw.getCurrentFrame():newChild{title="smth",args={"2021.11"}}) -- =p.BoxDate(mw.getCurrentFrame():newChild{title="smth",args={"11.2021"}}) function p.BoxDate( frame ) local args = getArgs(frame, { frameOnly = true }) local txtDateIn, strFormat = args[1], args[2] local txtDateOut, date, status = p.bxDate(txtDateIn, strFormat, params) if status.brk then return error(status.errorText) else return txtDateOut end end function p.bxDate( txtDateIn , strFormat, params ) -- к отладке local txtDateOut, date, status = "", {}, {brk = false, errorCat = "", errorText = ""} strFormat = strFormat or "j xg Y" -- заглушка - таблица параметров на будущее params = params or {} if not txtDateIn then status.errorText = e.no_data status.errorCat = category.no_parameters status.brk = true else -- заполнение служебных таблиц filling_months(mnlang, month_lang) end if not status.brk then -- парсинг входящей даты по шаблону date = parse_date(txtDateIn) -- заменить сообщения об ошибках на списочные if not (date.year and type(date.year) == 'number') then status.errorText = string.format(e.box_date,txtDateIn) status.errorCat = category.incomplete_parameters status.brk = true end if not inbord(date.month,1,12) then status.errorText = string.format(e.box_date,txtDateIn) status.errorCat = category.incomplete_parameters status.brk = true end if not date.day and string.find(strFormat,"[dDjlNwzW]") then strFormat = trim(string.gsub(string.gsub(strFormat,"xg","F"),"[dDjlNwzW]","")) elseif not date.day then elseif not inbord(date.day,1,month_end_day(date.month,date.year)) then status.errorText = string.format(e.box_date,txtDateIn) status.errorCat = category.incomplete_parameters status.brk = true end end if not status.brk then txtDateOut = mwlang:formatDate(strFormat,tCon({date.year,date.month,date.day},"-"),true) end return txtDateOut, date, status end function p.ToDate( frame ) -- возможно неиспользуемая local args = getArgs(frame, { frameOnly = true }) local mwlang = mw.getContentLanguage() local datein = args[1] local format = "j xg Y" if not string.match(datein, "%p") then return datein elseif not args[2] then else format = args[2] end return mwlang:formatDate(format,datein,true) end -- =p.unitime(mw.getCurrentFrame():newChild{title="smth",args={"−1:30","1"}}) function p.unitime( frame ) local args = getArgs(frame, { frameOnly = true }) local DST = 0 if not args[2] then else DST = 1 end local utcin = "" local input = args[1] if not input then return "" end if inlist(input:upper(),tzs_names) then utcin = known_tzs[input:upper()] elseif (string.sub(input:upper(),1,3) == 'UTC') and (string.len(input) < 10) then utcin = string.sub(input,4) else if string.sub(input,1,1) == '[' or string.sub(input,1,1) == '{' or string.sub(input,1,1):upper() == 'U' or string.sub(input,1,1):upper() == 'M' then return input -- elseif not string.find(string.upper(string.sub(input,1,1)),"[\65-\90]") or -- not string.find(string.upper(string.sub(input,1,1)),"[\192-\223]") then -- return input else utcin = input end end -- elseif string.sub(input,1,3) ~= "−" then utcin = input -- or not (not input:find("[А-я]")) при наличии в строке юникода не работает local output = "" if DST == 0 then output = utc(utcin) else output = utc(utcin) .. ", [[летнее время|летом]] " .. utc(utcin,DST) end return output end -- УСТАРЕЛО -- =p.OldDate(mw.getCurrentFrame():newChild{title="smth",args={"20.02.2020","ю",["bc"]="1",["wd"]="1",["wy"]="1",["sq_brts"]="1",["yearmark"]="г."}}) function p.OldDate( frame ) local args = getArgs(frame, { frameOnly = true }) if not args[1] then return err end local gdate, jdate = {}, {} local strin = args[1] local cal = args[2]:lower() or "г" local bc = is(args["bc"]) local wd = is(args["wd"]) local wm = is(args["wm"]) local wy = is(args["wy"]) if not wd then wm = false end local sq_brts = is(args["sq_brts"]) local yearmark = "года" if yesno(args["yearmark"]) then elseif yesno(args["yearmark"]) == false then yearmark = "" else yearmark = trim(args["yearmark"]) or "года" end -- local infocard = is(args["infocard"]) -- local catName = args["catName"] or false local datein = numstr2date(strin) datein.year = astroyear(datein.year, bc) jdate, gdate = recalc(datein,cal) return double_couple(jdate, gdate, wd, wm, wy, sq_brts, yearmark) end -- =p.NewDate(mw.getCurrentFrame():newChild{title="Salt",args={"2020-02-20"}}) -- =p.NewDate(mw.getCurrentFrame():newChild{title="smth",args={"20.02.2020","ю",["bc"]="1",["wd"]="1",["wy"]="1",["sq_brts"]="1",["yearmark"]="г."}}) -- =p.NewDate(mw.getCurrentFrame():newChild{title="smth",args={"20.02.2020",["bc"]="0",["wd"]="1",["wy"]="1",["sq_brts"]="0",["yearmark"]=""}}) function p.NewDate( frame ) local args = getArgs(frame, { frameOnly = true }) if not args[1] then return err end local strin = args[1] local year, month, day if not not strin:match( "(-?%d%d%d%d%d)-(%d%d)-(%d%d)" ) then year, month, day = strin:match( "(-?%d%d%d%d%d)-(%d%d)-(%d%d)" ) elseif not not strin:match( "(-?%d+)-(%d+)-(%d+)" ) then year, month, day = strin:match( "(-?%d+)-(%d+)-(%d+)" ) elseif not not strin:match( "(%d%d)%.(%d%d)%.(-?%d%d%d%d%d)" ) then day, month, year = strin:match( "(%d%d)%.(%d%d)%.(-?%d%d%d%d%d)" ) elseif not not strin:match( "(%d+)%.(%d+)%.(-?%d+)" ) then day, month, year = strin:match( "(%d+)%.(%d+)%.(-?%d+)" ) end if not year then return error(args[1] .. " не подходит под форматы yyyy-mm-dd или dd.mm.yyyy") end local cal = "г" if (not args[2]) or (args[2] == "") then cal = "г" else cal = args[2]:lower() end local bc,wd,wm,wy,sq_brts = is(args["bc"]), is(args["wd"]), is(args["wd"]) and is(args["wm"]), is(args["wy"]), is(args["sq_brts"]) year = astroyear(purif(year),bc) local datein = {["year"]=purif(year), ["month"]=purif(month), ["day"]=purif(day)} local jdate, gdate = recalc(datein,cal) local yearmark = "года" local ym = args["yearmark"] or "" if yesno(ym) then elseif yesno(ym) == false then yearmark = "" else if not not ym:match("(%d+)") then error("Цифры в обозначении года: " .. ym) else yearmark = trim(ym) or "года" end end return double_couple(jdate, gdate, wd, wm, wy, sq_brts, yearmark) end -- =p.Test(mw.getCurrentFrame():newChild{title="smth",args={}}) -- =p.Test(mw.getCurrentFrame():newChild{title="smth",args={"3","июня",nil,"21","мая"}}) -- =p.Test(mw.getCurrentFrame():newChild{title="smth",args={"28 августа","","1916 года","15"}}) -- =p.Test(mw.getCurrentFrame():newChild{title="smth",args={"3","июня","1900","21","мая"}}) -- =p.Test(mw.getCurrentFrame():newChild{title="smth",args={"6","июня","1889 год","25","мая"}}) -- =p.Test(mw.getCurrentFrame():newChild{title="smth",args={"28","ноября","1917","15"}}) -- =p.Test(mw.getCurrentFrame():newChild{title="smth",args={"28 августа","nil","1916 года","15"}}) -- =p.Test(mw.getCurrentFrame():newChild{title="smth",args={"4","января","1915","22","декабря","1914 года"}}) -- {{OldStyleDate|день (НС)|месяц (НС)|год (НС)|день (СС)|месяц (СС)|год (СС)}} function p.Test( frame ) local args = getArgs(frame, { frameOnly = true }) -- необходима проверка и замена nil на " " --[[mw.log((args[1] or "") .. " " .. (args[2] or "") .. " " .. (args[3] or "") .. " " .. (args[4] or "") .. " " .. (args[5] or "") .. " " .. (args[6] or "")) ]]-- local ingdate = triple_txt2date(args[1],args[2],args[3]) local injdate = triple_txt2date(args[4],args[5],args[6]) local j1date, g1date, j2date, g2date = init(4) mw.log("ingdate-".. (undate(ingdate) or "")) mw.log("injdate-".. (undate(injdate) or "")) local bc,wd,wm,wy,sq_brts,ny = is(args["bc"]), is(args["wd"]), is(args["wd"]) and is(args["wm"]), is(args["wy"]), is(args["sq_brts"]), is(args["ny"]) -- подавление формата для локальных тестов local wd, wm, wy = true, true, true local yearmark = "года" local ym = args["yearmark"] or ((mw.ustring.match((args[3] or ""),"(%a+)") or mw.ustring.match((args[6] or ""),"(%a+)")) or "") -- mw.log("ym " .. ym) if yesno(ym) then elseif yesno(ym) == false then yearmark = "" else if not not ym:match("(%d+)") then error("Цифры в обозначении года: " .. ym) else yearmark = trim(ym) or "года" end end if isdate(ingdate) or isdate(injdate) then if isdate(ingdate) then j1date, g1date = recalc(ingdate,"g") ingdate["full"] = true end if isdate(injdate) then j2date, g2date = recalc(injdate,"j") injdate["full"] = true end if ispartdate(ingdate) and ispartdate(injdate) then mw.log("📏 " .. dmdist(ingdate,injdate)) mw.log("📏 " .. dmdist(j1date,g1date)) mw.log("📏 " .. dmdist(j2date,g2date)) mw.log("📏 " .. dmdist(ingdate,g1date)) mw.log("📏 " .. dmdist(injdate,j2date)) end end if ny then if isyear(j1date) then else j1date["year"] = "" end if isyear(j2date) == nil then else j2date["year"] = "" end if isyear(g1date) == nil then else g1date["year"] = "" end if isyear(g2date) == nil then else g2date["year"] = "" end end if (isdate(j1date) and isdate(g1date) and isdate(j2date) and isdate(g2date)) then if ((j1date.year == j2date.year) and (j1date.month == j2date.month) and (j1date.day == j2date.day)) then return double_couple(j1date, g1date, wd, wm, wy, sq_brts, yearmark) else mw.log("📏 " .. (tostring(dmdist(ingdate,injdate)) or "")) return glue(args[1],args[2],args[3],args[4],args[5],args[6]) -- категория (предположительная разница в днях) и частичный вывод end elseif isdate(j1date) and isdate(g1date) then return double_couple(j1date, g1date, wd, wm, wy, sq_brts, yearmark) -- категория плюс частичная проверка elseif isdate(j2date) and isdate(g2date) then return double_couple(j2date, g2date, wd, wm, wy, sq_brts, yearmark) -- категория плюс частичная проверка elseif (ispartdate(ingdate) and ispartdate(injdate)) then mw.log("ingdate ".. (undate(ingdate) or "")) mw.log("injdate ".. (undate(injdate) or "")) mw.log("j1date " .. (undate(j1date ) or "")) mw.log("j2date " .. (undate(j2date ) or "")) mw.log("g1date " .. (undate(g1date ) or "")) mw.log("g2date " .. (undate(g2date ) or "")) mw.log("📏 " .. (tostring(partdist(ingdate,injdate)) or "").. " — " .. (tostring(partdist(injdate,ingdate)) or "")) return glue(args[1],args[2],args[3],args[4],args[5],args[6]) -- частичный или полный вывод, категория else mw.log("ingdate ".. (undate(ingdate) or "")) mw.log("injdate ".. (undate(injdate) or "")) mw.log("j1date " .. (undate(j1date ) or "")) mw.log("j2date " .. (undate(j2date ) or "")) mw.log("g1date " .. (undate(g1date ) or "")) mw.log("g2date " .. (undate(g2date ) or "")) return err .. category.incomplete_parameters end end return p a4a91f134ad3e3b246b3a6681a4ae438da766df4 Модуль:Infocards 828 55 107 2023-05-29T15:51:46Z wikipedia:ru>Putnik 0 переиспользование функции форматирования из [[Module:Dates]] для унификации Scribunto text/plain local infocards = {} local calculateAge = true local dateCat = require( 'Module:Infocards/dateCat' ) local moduleDates = require( 'Module:Dates' ) --[[ Helper function that populates the argument list given that user may need to use a mix of named and unnamed parameters. This is relevant because named parameters are not identical to unnamed parameters due to string trimming, and when dealing with strings we sometimes want to either preserve or remove that whitespace depending on the application. ]] function infocards._getParameters( frame_args, arg_list ) local new_args = {} local index = 1 local value for i,arg in ipairs( arg_list ) do value = frame_args[arg] if value == nil then value = frame_args[index] index = index + 1 end new_args[arg] = value end return new_args end function infocards.isBlank( someString ) return someString == nil or mw.ustring.match(someString, '^%s*$') ~= nil end function infocards.isDate ( frame ) local new_args = infocards._getParameters( frame.args, {'s', 't', 'f'} ) local s = new_args['s'] or '' local t = new_args['t'] or '' local f = new_args['f'] or '' local result = infocards.isDateImpl ( s ) if (result) then return t else return f end end function infocards.isDateImpl ( s ) local converted = infocards.convertToDate ( s ) return converted ~= nil end function infocards.dateOfBirth( frame ) local new_args = infocards._getParameters( frame.args, {'dateOfBirth', 'dateOfDeath', 'suppressAge', 'nocat'} ) local dateOfBirth = new_args['dateOfBirth'] or '' local dateOfDeath = new_args['dateOfDeath'] or '' local suppressAge = new_args['suppressAge'] or '' local nocat = new_args['nocat'] or mw.title.getCurrentTitle().nsText return infocards.dateOfBirthImpl( dateOfBirth, dateOfDeath, suppressAge, nocat ) end function infocards.dateOfBirthImpl( dateOfBirth, dateOfDeath, suppressAge, nocat ) local appendToCategory = infocards.isBlank( nocat ) if ( infocards.isBlank( dateOfBirth ) ) then if ( appendToCategory ) then return dateCat.categoryNoBirthDate else return '' end end if ( mw.ustring.match( dateOfBirth, '^%s*неизвестн.%s*$' ) ~= nil or mw.ustring.match( dateOfBirth, '^%s*%?%s*$' ) ~= nil ) then if ( appendToCategory ) then return "''неизвестно''" .. dateCat.categoryUnknownBirthDate else return "''неизвестно''" end end local appendAge = not (suppressAge ~= '' or not calculateAge) and infocards.isBlank( dateOfDeath ) local parsedDate = infocards.convertToDate ( dateOfBirth ) if ( parsedDate == nil ) then --[[ Temporary hack in order to enable export dates to wikidata ]] local bDateStart = '<span class="no-wikidata" data-wikidata-property-id="P569">' local bDateEnd = '</span>' if ( appendToCategory ) then return bDateStart .. dateOfBirth .. bDateEnd .. dateCat.categoryManualWikification else return bDateStart .. dateOfBirth .. bDateEnd end end local result = infocards.formatDateImpl ( parsedDate, 'bday', appendToCategory and 'Родившиеся' or nil ) if ( appendAge ) then -- TODO: месяцы и дни для (нескольких) новорождённых (см. новейшие [[Категория:Родившиеся в ГГГГ году]]) local age = infocards.age ( parsedDate, os.date("*t") ) if ( age and age < 125) then result = result .. ' <span class="nowrap">(' .. age .. ' ' .. mw.language.new( 'ru' ):plural( age, 'год', 'года', 'лет') .. ')</span>' end if ( appendToCategory ) then if (not age and parsedDate and parsedDate.year ) then age = os.date('*t').year - parsedDate.year -- при неточной дате end if ( age ) then if ( age > 115 ) then result = result .. dateCat.categoryBigCurrentAge elseif ( age >= 0 ) then result = result .. dateCat.categoryBiographiesOfLivingPersons else result = result .. dateCat.categoryNegativeAge end end end end return result end function infocards.dateOfDeath( frame ) local new_args = infocards._getParameters( frame.args, {'dateOfBirth', 'dateOfDeath', 'nocat'} ) local dateOfBirth = new_args['dateOfBirth'] or '' local dateOfDeath = new_args['dateOfDeath'] or '' local nocat = new_args['nocat'] or mw.title.getCurrentTitle().nsText return infocards.dateOfDeathImpl( dateOfBirth, dateOfDeath, nocat ) end function infocards.dateOfDeathImpl( dateOfBirth, dateOfDeath, nocat ) if ( infocards.isBlank( dateOfDeath ) ) then return '' end local appendToCategory = infocards.isBlank( nocat ) if ( mw.ustring.match( dateOfDeath, '^%s*неизвестн.%s*$' ) ~= nil or mw.ustring.match( dateOfDeath, '^%s*%?%s*$' ) ~= nil ) then if ( appendToCategory ) then return "''неизвестно''" .. dateCat.categoryUnknownDeathDate else return "''неизвестно''" end end local parsedDateOfBirth = infocards.convertToDate ( dateOfBirth ) local parsedDateOfDeath = infocards.convertToDate ( dateOfDeath ) if ( parsedDateOfDeath == nil ) then --[[ Temporary hack in order to enable export dates to wikidata ]] local dDateStart = '<span class="no-wikidata" data-wikidata-property-id="P570">' local dDateEnd = '</span>' if ( appendToCategory ) then return dDateStart .. dateOfDeath .. dDateEnd .. dateCat.categoryManualWikification else return dDateStart .. dateOfDeath .. dDateEnd end end local result = infocards.formatDateImpl ( parsedDateOfDeath, 'dday', appendToCategory and 'Умершие' or nil ) if ( calculateAge ) then local age = infocards.age ( parsedDateOfBirth, parsedDateOfDeath ) if ( age and age > 0 ) then result = result .. ' <span class="nowrap">(' .. age .. ' ' .. mw.language.new( 'ru' ):plural( age, 'год', 'года', 'лет') .. ')</span>' end -- returns category to recently deceased persons local unixAvailable, unixDateOfDeath = pcall(function() local r = os.time(parsedDateOfDeath) if ( r ~= os.time() ) then return r end error() end) if (appendToCategory) then if ( unixAvailable and os.time() - unixDateOfDeath < 31536000 ) then result = result .. dateCat.categoryRecentlyDeceased elseif (age and age < 0) then result = result .. dateCat.categoryNegativeAge end end end return result end function infocards.age( parsedBirthDate, parsedFinishDate ) if ( parsedBirthDate == nil or parsedFinishDate == nil ) then return nil end local bd = parsedBirthDate["day"] local bm = parsedBirthDate["month"] local by = parsedBirthDate["year"] local dd = parsedFinishDate["day"] local dm = parsedFinishDate["month"] local dy = parsedFinishDate["year"] if ( bd and bm and by and dd and dm and dy ) then if ( dm > bm or ( dm == bm and dd >= bd ) ) then return dy - by else return dy - by - 1 end else return nil end end function infocards.formatDateImpl( parsedDate, infocardClass, categoryNamePrefix ) local datePart = '<span class="nowrap">' --Temporary hack in order to enable export dates to wikidata if infocardClass == "bday" then datePart = '<span class="no-wikidata" data-wikidata-property-id="P569">' elseif infocardClass == "dday" then datePart = '<span class="no-wikidata" data-wikidata-property-id="P570">' end local t1 = { day = parsedDate.osday, month = parsedDate.osmonth, year = parsedDate.osyear } local t2 = { day = parsedDate.day, month = parsedDate.month, year = parsedDate.year } datePart = datePart .. moduleDates.formatWikiImpl( t1, t2, infocardClass, categoryNamePrefix ) datePart = datePart .. '</span>' return datePart end function infocards.convertToDate( possibleDateString ) possibleDateString = mw.ustring.gsub( possibleDateString, '−', '-') local simpleDate = mw.ustring.match(possibleDateString, '^%s*([%-%d%.]+)%s*$', 0) if ( simpleDate ) then return infocards.convertToDateNewStylePart( simpleDate ) end local complexDate1, complexDate2 = mw.ustring.match(possibleDateString, '^%s*([%-%d%.]+)%s*%(([%-%d%.]+)%)%s*$', 0) if ( complexDate1 and complexDate2) then local table1 = infocards.convertToDateNewStylePart( complexDate1 ) local table2 = infocards.convertToDateOldStylePart( complexDate2 ) if ( table1 and table2 ) then return { year = table1["year"], month = table1["month"], day = table1["day"], osyear = table2["year"], osmonth = table2["month"], osday = table2["day"] } else return nil end end return nil end function infocards.convertToDateNewStylePart( possibleDateString ) local ny = mw.ustring.match(possibleDateString, '^(%-?%d+)$', 0) if (ny ~= nil) then return {year = tonumber(ny)} end return infocards.convertToDateCommonPart( possibleDateString ) end function infocards.convertToDateOldStylePart( possibleDateString ) local nd = mw.ustring.match(possibleDateString, '^(%-?%d+)$', 0) if (nd ~= nil) then return {day = tonumber(nd)} end return infocards.convertToDateCommonPart( possibleDateString ) end function infocards.convertToDateCommonPart( possibleDateString ) local sDay, sMonth, sYear local day, month, year sDay, sMonth, sYear = mw.ustring.match( possibleDateString, '^(%d?%d)%.(%d?%d)%.(%-?%d+)$', 0 ) if sDay ~= nil and sMonth ~= nil and sYear ~= nil then day = tonumber( sDay ) month = tonumber( sMonth ) year = tonumber( sYear ) if day >= 1 and day <= 32 and month >= 1 and month <= 12 then return { day = day, month = month, year = year } end end sDay, sMonth = mw.ustring.match( possibleDateString, '^(%d?%d)%.(%d?%d+)$', 0 ) if sDay ~= nil and sMonth ~= nil then day = tonumber( sDay ) month = tonumber( sMonth ) if day >= 1 and day <= 32 and month >= 1 and month <= 12 then return { day = day, month = month } end end sMonth, sYear = mw.ustring.match( possibleDateString, '^(%d?%d)%.(%-?%d+)$', 0 ) if sMonth ~= nil and sYear ~= nil then month = tonumber( sMonth ) year = tonumber( sYear ) if month >= 1 and month <= 12 then return { month = month, year = year } end end return nil end return infocards 6c1e746d6605d4d101f6aa9fd3e4824b60c64ef7 Шаблон:Карточка/оригинал имени 10 45 87 2023-07-04T10:53:34Z wikipedia:ru>Wikisaurus 0 wikitext text/x-wiki {{wikidata|p1559[language!:ru]|{{{1|}}}|before={{{before|}}}|separator=<br>|conjunction=<br>|monolingualLangTemplate={{{monolingualLangTemplate|lang}}}|from={{{from|}}}}}<!-- -->{{#if:{{NAMESPACE}}||{{#if:{{{1|}}}|{{#ifeq:{{#invoke:String|find|{{{1|}}}|span}}|0|[[Категория:Википедия:Статьи с оригиналом имени без шаблона lang-XX]]}}}}}}<noinclude>{{doc}}</noinclude> a294e3f7f61c5206ca5671b72e21804d7a32fcbc Шаблон:Флагификация/флагификация 10 43 83 2023-07-28T15:53:15Z wikipedia:ru>Stjn 0 не изменять размер в мобильной версии (на всякий случай) wikitext text/x-wiki <span class="nowrap" data-sort-value="{{{shortname alias|{{{alias}}}}}}"><span class="flagicon">[[File:{{{flag alias-{{{variant}}}|{{{flag alias}}}}}}|class=noresize|link=|alt=|{{#if: {{{размер|}}} | {{{размер}}} | 22x20px }}|{{{border-{{{variant}}}|{{{border|border}}}}}}]]</span>&nbsp;[[{{{alias}}}|<span class="wrap">{{{shortname alias-{{{variant}}}|{{{shortname alias|{{{alias}}}}}}}}}</span>]]</span><noinclude>{{doc}}</noinclude> 8403cde4528b4d7df313d2e82aeb40b0bb66c2c2 Шаблон:Сначала имя 10 51 99 2023-11-15T18:34:52Z wikipedia:ru>Stjn 0 читаемость wikitext text/x-wiki {{safesubst:<noinclude />#ifexpr: {{safesubst:<noinclude />str find|{{safesubst:<noinclude />До символа|{{{1}}}|(}}|,}} = -1 <!-- -->|{{safesubst:<noinclude />До символа|{{{1}}}|(}}<!-- -->|{{safesubst:<noinclude />trim|{{safesubst:<noinclude />После символа|{{safesubst:<noinclude />До символа|{{{1}}}|(}}|,}}}} {{safesubst:<noinclude />До символа|{{safesubst:<noinclude />До символа|{{{1}}}|(}}|,}}<!-- -->}}<noinclude> {{doc}} </noinclude> c3a2e3e13dba0ae595a7c147ca692be2eb183f38 Шаблон:Легенда 10 88 173 2024-01-07T19:41:21Z wikipedia:ru>Stjn 0 у нас ещё и это невозможно wikitext text/x-wiki <includeonly><!-- --><templatestyles src="Шаблон:Легенда/styles.css" /><!-- --><span class="ts-legend {{#ifeq: {{{3|}}} | inline | ts-legend-inline }} legend" style="{{#if: {{{8|}}} | font-size: {{{8}}}; }}"><!-- --><span class="ts-legend-color legend-color mw-no-invert {{{class|}}}" style="<!-- -->{{#if: {{{4|}}} | border: {{{4}}}; | {{#if: {{{1|}}} | border: 0px solid {{{1}}};}}}}<!-- -->{{#if: {{{5|}}} | border-radius: {{{5}}};}}<!-- -->{{#if: {{{1|}}} | background: {{{1}}};}}<!-- -->{{#if: {{{6|}}} | color: {{{6}}}; }}<!-- -->" {{#if: {{{9|}}} | title="{{{9}}}" | {{#if: {{{1|}}} | title="{{{1}}}"}} }}><!-- -->{{#if: {{{alt|}}}{{{7|}}} | <span class="ts-legend-text legend-text" style="{{#if:{{{alt|}}} | color:{{{1|}}};}}font-family: monospace, monospace;">{{#if: {{{7|}}} | {{{7}}} | &nbsp;&nbsp;&nbsp;&nbsp; }}</span> }}<!-- --></span><!-- -->&nbsp;{{{2|}}}<!-- --></span><!-- --></includeonly><noinclude> {{doc}} <!-- Пожалуйста, добавляйте категории и интервики на страницу документации! --> </noinclude> 362927ba47a0f5b2dcf9de3f17dbfbc8eaba4b89 Шаблон:Легенда/styles.css 10 110 217 2024-01-07T20:03:02Z wikipedia:ru>Q-bit array 0 Защитил страницу [[Шаблон:Легенда/styles.css]]: критический шаблон или модуль ([Редактирование=администраторы и инженеры] (бессрочно) [Переименование=администраторы и инженеры] (бессрочно)) text text/plain /* Скопировано из [[:en:Template:Legend/styles.css]] с изменениями */ .ts-legend { page-break-inside: avoid; break-inside: avoid-column; display: block; font-size: 90%; } .thumb .ts-legend, figcaption .ts-legend { font-size: inherit; } .ts-legend-inline { display: inline-block; } .ts-legend-color { display: inline-block; min-width: 1.25em; height: 1.25em; line-height: 1.25; margin: 1px 0; text-align: center; border: 1px solid black; color: black; vertical-align: middle; } /*empty for now, but part of the design!*/ /*.ts-legend-text {}*/ /* [[Категория:Шаблоны:Подстраницы CSS]] */ 92f4aefe4d4206899f554e9262090e50a27a5171 Модуль:Delink 828 39 75 2024-02-28T16:27:08Z wikipedia:ru>Dima st bk 0 sync with enwiki, see authors of this version https://en.wikipedia.org/w/index.php?title=Module:Delink&oldid=1208348327 Scribunto text/plain -- This module de-links most wikitext. require("strict") local yesno = require("Module:Yesno") local p = {} local getArgs local function delinkReversePipeTrick(s) if s:match("^%[%[|.*[|\n]") then -- Check for newlines or multiple pipes. return s end return s:match("%[%[|(.*)%]%]") end local function delinkPipeTrick(s) -- We need to deal with colons, brackets, and commas, per [[Help:Pipe trick]]. -- First, remove the text before the first colon, if any. if s:match(":") then s = s:match("%[%[.-:(.*)|%]%]") -- If there are no colons, grab all of the text apart from the square brackets and the pipe. else s = s:match("%[%[(.*)|%]%]") end -- Next up, brackets and commas. if s:match("%(.-%)$") then -- Brackets trump commas. s = s:match("(.-) ?%(.-%)$") elseif s:match(",") then -- If there are no brackets, display only the text before the first comma. s = s:match("(.-),.*$") end return s end -- Return wikilink target |wikilinks=target local function getDelinkedTarget(s) local result = s -- Deal with the reverse pipe trick. if result:match("%[%[|") then return delinkReversePipeTrick(result) end result = mw.uri.decode(result, "PATH") -- decode percent-encoded entities. Leave underscores and plus signs. result = mw.text.decode(result, true) -- decode HTML entities. -- Check for bad titles. To do this we need to find the -- title area of the link, i.e. the part before any pipes. local target_area if result:match("|") then -- Find if we're dealing with a piped link. target_area = result:match("^%[%[(.-)|.*%]%]") else target_area = result:match("^%[%[(.-)%]%]") end -- Check for bad characters. if mw.ustring.match(target_area, "[%[%]<>{}%%%c\n]") and mw.ustring.match(target_area, "[%[%]<>{}%%%c\n]") ~= "?" then return s end return target_area end local function getDelinkedLabel(s) local result = s -- Deal with the reverse pipe trick. if result:match("%[%[|") then return delinkReversePipeTrick(result) end result = mw.uri.decode(result, "PATH") -- decode percent-encoded entities. Leave underscores and plus signs. result = mw.text.decode(result, true) -- decode HTML entities. -- Check for bad titles. To do this we need to find the -- title area of the link, i.e. the part before any pipes. local target_area if result:match("|") then -- Find if we're dealing with a piped link. target_area = result:match("^%[%[(.-)|.*%]%]") else target_area = result:match("^%[%[(.-)%]%]") end -- Check for bad characters. if mw.ustring.match(target_area, "[%[%]<>{}%%%c\n]") and mw.ustring.match(target_area, "[%[%]<>{}%%%c\n]") ~= "?" then return s end -- Check for categories, interwikis, and files. local colon_prefix = result:match("%[%[(.-):.*%]%]") or "" -- Get the text before the first colon. local ns = mw.site.namespaces[colon_prefix] -- see if this is a known namespace if mw.language.isKnownLanguageTag(colon_prefix) or (ns and (ns.canonicalName == "File" or ns.canonicalName == "Category")) then return "" end -- Remove the colon if the link is using the [[Help:Colon trick]]. if result:match("%[%[:") then result = "[[" .. result:match("%[%[:(.*%]%])") end -- Deal with links using the [[Help:Pipe trick]]. if mw.ustring.match(result, "^%[%[[^|]*|%]%]") then return delinkPipeTrick(result) end -- Find the display area of the wikilink if result:match("|") then -- Find if we're dealing with a piped link. result = result:match("^%[%[.-|(.+)%]%]") -- Remove new lines from the display of multiline piped links, -- where the pipe is before the first new line. result = result:gsub("\n", "") else result = result:match("^%[%[(.-)%]%]") end return result end local function delinkURL(s) -- Assume we have already delinked internal wikilinks, and that -- we have been passed some text between two square brackets [foo]. -- If the text contains a line break it is not formatted as a URL, regardless of other content. if s:match("\n") then return s end -- Check if the text has a valid URL prefix and at least one valid URL character. local valid_url_prefixes = {"//", "http://", "https://", "ftp://", "gopher://", "mailto:", "news:", "irc://"} local url_prefix for _ ,v in ipairs(valid_url_prefixes) do if mw.ustring.match(s, '^%[' .. v ..'[^"%s].*%]' ) then url_prefix = v break end end -- Get display text if not url_prefix then return s end s = s:match("^%[" .. url_prefix .. "(.*)%]") -- Grab all of the text after the URL prefix and before the final square bracket. s = s:match('^.-(["<> ].*)') or "" -- Grab all of the text after the first URL separator character ("<> ). s = mw.ustring.match(s, "^%s*(%S.*)$") or "" -- If the separating character was a space, trim it off. local s_decoded = mw.text.decode(s, true) if mw.ustring.match(s_decoded, "%c") then return s end return s_decoded end local function delinkLinkClass(text, pattern, delinkFunction) if type(text) ~= "string" then error("Attempt to de-link non-string input.", 2) end if type(pattern) ~= "string" or mw.ustring.sub(pattern, 1, 1) ~= "^" then error('Invalid pattern detected. Patterns must begin with "^".', 2) end -- Iterate over the text string, and replace any matched text. using the -- delink function. We need to iterate character by character rather -- than just use gsub, otherwise nested links aren't detected properly. local result = "" while text ~= "" do -- Replace text using one iteration of gsub. text = mw.ustring.gsub(text, pattern, delinkFunction, 1) -- Append the left-most character to the result string. result = result .. mw.ustring.sub(text, 1, 1) text = mw.ustring.sub(text, 2, -1) end return result end function p._delink(args) local text = args[1] or "" if yesno(args.markers) == true then text = mw.text.killMarkers(text) -- [[Help:Strip markers]] end if yesno(args.refs) == true then -- Remove any [[Help:Strip markers]] representing ref tags. In most situations -- this is not a good idea - only use it if you know what you are doing! text = mw.ustring.gsub(text, "UNIQ%w*%-ref%-%d*%-QINU", "") end if not (yesno(args.comments) == false) then text = text:gsub("<!%-%-.-%-%->", "") -- Remove html comments. end if not (yesno(args.wikilinks) == false) and args.wikilinks ~= "target" then -- De-link wikilinks and return the label portion of the wikilink. text = delinkLinkClass(text, "^%[%[.-%]%]", getDelinkedLabel) elseif args.wikilinks == "target" then -- De-link wikilinks and return the target portions of the wikilink. text = delinkLinkClass(text, "^%[%[.-%]%]", getDelinkedTarget) end if not (yesno(args.urls) == false) then text = delinkLinkClass(text, "^%[.-%]", delinkURL) -- De-link URLs. end if not (yesno(args.whitespace) == false) then -- Replace single new lines with a single space, but leave double new lines -- and new lines only containing spaces or tabs before a second new line. text = mw.ustring.gsub(text, "([^\n \t][ \t]*)\n([ \t]*[^\n \t])", "%1 %2") text = text:gsub("[ \t]+", " ") -- Remove extra tabs and spaces. end return text end function p.delink(frame) if not getArgs then getArgs = require('Module:Arguments').getArgs end return p._delink(getArgs(frame, {wrappers = 'Template:Delink'})) end return p eb6cae0d369f288b0b1600633d9bf7874cefdcbc Модуль:Message box 828 14 25 2024-03-25T18:05:03Z wikipedia:ru>Stjn 0 fix Scribunto text/plain -- This is a meta-module for producing message box templates, including -- {{mbox}}, {{ambox}}, {{imbox}}, {{tmbox}}, {{ombox}}, {{cmbox}} and {{fmbox}}. -- Load necessary modules. require('strict') local getArgs local categoryHandler = require('Module:Category handler')._main local yesno = require('Module:Yesno') local boxDate = require('Module:Calendar').bxDate; -- Get a language object for formatDate and ucfirst. local lang = mw.language.getContentLanguage() -- Define constants local CONFIG_MODULE = 'Module:Message box/configuration' -------------------------------------------------------------------------------- -- Helper functions -------------------------------------------------------------------------------- local function getTitleObject(...) -- Get the title object, passing the function through pcall -- in case we are over the expensive function count limit. local success, title = pcall(mw.title.new, ...) if success then return title end end local function union(t1, t2) -- Returns the union of two arrays. local vals = {} for i, v in ipairs(t1) do vals[v] = true end for i, v in ipairs(t2) do vals[v] = true end local ret = {} for k in pairs(vals) do table.insert(ret, k) end table.sort(ret) return ret end local function getArgNums(args, prefix) local nums = {} for k, v in pairs(args) do local num = mw.ustring.match(tostring(k), '^' .. prefix .. '([1-9]%d*)$') if num then table.insert(nums, tonumber(num)) end end table.sort(nums) return nums end -- локальная обёртка, игнорирует таблицу с номерами дня, месяца и года local function formatDate(txtDateIn, strFormat, params) local txtDateOut, date, status = boxDate(txtDateIn, strFormat, params) if status.brk then return error(status.errorText) else return txtDateOut end end -------------------------------------------------------------------------------- -- Box class definition -------------------------------------------------------------------------------- local MessageBox = {} MessageBox.__index = MessageBox function MessageBox.new(boxType, args, cfg) args = args or {} local obj = {} -- Set the title object and the namespace. obj.title = getTitleObject(args.page) or mw.title.getCurrentTitle() -- Set the config for our box type. obj.cfg = cfg[boxType] if not obj.cfg then local ns = obj.title.namespace -- boxType is "mbox" or invalid input if ns == 0 then obj.cfg = cfg.ambox -- main namespace elseif ns == 6 then obj.cfg = cfg.imbox -- file namespace elseif ns == 14 then obj.cfg = cfg.cmbox -- category namespace else local nsTable = mw.site.namespaces[ns] if nsTable and nsTable.isTalk then obj.cfg = cfg.tmbox -- any talk namespace else obj.cfg = cfg.ombox -- other namespaces or invalid input end end end -- Set the arguments, and remove all blank arguments except for the ones -- listed in cfg.allowBlankParams. do local newArgs = {} for k, v in pairs(args) do if v ~= '' then newArgs[k] = v end end for i, param in ipairs(obj.cfg.allowBlankParams or {}) do newArgs[param] = args[param] end obj.args = newArgs end -- Define internal data structure. obj.categories = {} obj.classes = {} return setmetatable(obj, MessageBox) end function MessageBox:addCat(ns, cat, sort) if not cat then return nil end if sort then cat = string.format('[[Категория:%s|%s]]', cat, sort) else cat = string.format('[[Категория:%s]]', cat) end self.categories[ns] = self.categories[ns] or {} table.insert(self.categories[ns], cat) end function MessageBox:addClass(class) if not class then return nil end table.insert(self.classes, class) end function MessageBox:setParameters() local args = self.args local cfg = self.cfg -- Get type data. self.type = args.type local typeData = cfg.types[self.type] self.invalidTypeError = cfg.showInvalidTypeError and self.type and not typeData typeData = typeData or cfg.types[cfg.default] self.typeClass = typeData.class self.typeImage = typeData.image -- Find if the box has been wrongly substituted. self.isSubstituted = cfg.substCheck and args.subst == 'SUBST' -- Find whether we are using a small message box. self.isSmall = cfg.allowSmall and ( cfg.smallParam and args.small == cfg.smallParam or not cfg.smallParam and yesno(args.small) ) -- Add attributes, classes and styles. self.id = args.id self.name = args.name if self.name then self:addClass('mbox-' .. string.gsub(self.name,' ','_')) end if yesno(args.plainlinks) ~= false then self:addClass('plainlinks') end for _, class in ipairs(cfg.classes or {}) do self:addClass(class) end if self.isSmall then self:addClass(cfg.smallClass or 'mbox-small') end self:addClass(self.typeClass) self:addClass(args.class) self.style = args.style self.attrs = args.attrs self.dataLabel1 = args['data-label-1'] self.dataLabel2 = args['data-label-2'] self.dataLabel3 = args['data-label-3'] self.dataValue1 = args['data-value-1'] self.dataValue2 = args['data-value-2'] self.dataValue3 = args['data-value-3'] -- Set text style. self.textstyle = args.textstyle -- Find if we are on the template page or not. This functionality is only -- used if useCollapsibleTextFields is set, or if both cfg.templateCategory -- and cfg.templateCategoryRequireName are set. self.useCollapsibleTextFields = cfg.useCollapsibleTextFields if self.useCollapsibleTextFields or cfg.templateCategory and cfg.templateCategoryRequireName then self.name = args.name if self.name then local templateName = mw.ustring.match( self.name, '^[tT][eE][mM][pP][lL][aA][tT][eE][%s_]*:[%s_]*(.*)$' ) or self.name templateName = ('Template:' .. templateName) or ('Шаблон:' .. templateName) self.templateTitle = getTitleObject(templateName) end self.isTemplatePage = self.templateTitle and mw.title.equals(self.title, self.templateTitle) end -- Process data for collapsible text fields. At the moment these are only -- used in {{ambox}}. if self.useCollapsibleTextFields then -- Get the self.issue value. if self.isSmall and args.smalltext then self.issue = args.smalltext else if args.sect and args.sect ~= '' or nil then local issue_sect = args.issue_sect issue_sect = type(issue_sect) == 'string' and issue_sect ~= '' and issue_sect or nil local text_sect = args.text_sect text_sect = type(text_sect) == 'string' and text_sect ~= '' and text_sect or nil local issues = {} table.insert(issues, issue_sect) table.insert(issues, text_sect) self.issue = table.concat(issues, ' ') else local issue = args.issue issue = type(issue) == 'string' and issue ~= '' and issue or nil local text = args.text text = type(text) == 'string' and text or nil local issues = {} table.insert(issues, issue) table.insert(issues, text) self.issue = table.concat(issues, ' ') end end -- Get the self.talk value. local talk = args.talk -- Show talk links on the template page or template subpages if the talk -- parameter is blank. if talk == '' and self.templateTitle and ( mw.title.equals(self.templateTitle, self.title) or self.title:isSubpageOf(self.templateTitle) ) then talk = '#' elseif talk == '' then talk = nil end if talk then -- If the talk value is a talk page, make a link to that page. Else -- assume that it's a section heading, and make a link to the talk -- page of the current page with that section heading. local talkTitle = getTitleObject(talk) local talkArgIsTalkPage = true if not talkTitle or not talkTitle.isTalkPage then talkArgIsTalkPage = false talkTitle = getTitleObject( self.title.text, mw.site.namespaces[self.title.namespace].talk.id ) end if talkTitle and talkTitle.exists then local talkText = 'Соответствующую дискуссию можно найти на' if talkArgIsTalkPage then talkText = string.format( '%s [[%s|%s]].', talkText, talk, talkTitle.prefixedText ) else talkText = string.format( '%s [[%s#%s|странице обсуждения]].', talkText, talkTitle.prefixedText, talk ) end self.talk = talkText end end -- Get other values. self.fix = args.fix ~= '' and args.fix or nil local date if args.date and args.date ~= '' then local status, result = pcall(formatDate, args.date) if status then date = string.format("(<span class='date'>%s</span>)", result) else date = string.format("<span class='error'>(Строка «%s» не является верной датой, пожалуйста, укажите дату в формате <code>ГГГГ-ММ-ДД</code>)</span>", args.date) end elseif args.date == '' and self.isTemplatePage then date = string.format("(<span class='date'>%s</span>)", formatDate( lang:formatDate('Y-m-d') ) ) -- тут возникновения ошибки, связанной с пользовательским вводом, не будет end if date then self.date = string.format(" <span class='mbox-date'>''%s''</span>", date) end self.info = args.info if yesno(args.removalnotice) then self.removalNotice = cfg.removalNotice end if args.shortFix then self.shortFix = args.shortFix end end -- Set the non-collapsible text field. At the moment this is used by all box -- types other than ambox, and also by ambox when small=yes. if self.isSmall then self.text = args.smalltext or args.text else self.text = args.text self.textsmall = args['text-small'] end -- Set the below row. self.below = cfg.below and args.below -- General image settings. self.imageCellDiv = not self.isSmall and cfg.imageCellDiv self.imageEmptyCell = cfg.imageEmptyCell if cfg.imageEmptyCellStyle then self.imageEmptyCellStyle = 'border:none;padding:0px;width:1px' end -- Left image settings. local imageLeft = self.isSmall and args.smallimage or args.image if cfg.imageCheckBlank and imageLeft ~= 'blank' and imageLeft ~= 'none' and imageLeft ~= '' or not cfg.imageCheckBlank and imageLeft ~= 'none' then self.imageLeft = imageLeft if not imageLeft then local imageSize = self.isSmall and (cfg.imageSmallSize or '30x30px') or cfg.imageSize or '40x40px' self.imageLeft = string.format('[[File:%s|%s|alt=]]', self.typeImage or 'Information icon4.svg', imageSize) end end -- Right image settings. local imageRight = self.isSmall and args.smallimageright or args.imageright if not (cfg.imageRightNone and imageRight == 'none') then self.imageRight = imageRight end -- set templatestyles self.base_templatestyles = cfg.templatestyles end function MessageBox:setMainspaceCategories() local args = self.args local cfg = self.cfg local date = nil if not cfg.allowMainspaceCategories then return nil end local nums = {} for _, prefix in ipairs{'cat', 'category', 'all'} do args[prefix .. '1'] = args[prefix] nums = union(nums, getArgNums(args, prefix)) end -- The following is roughly equivalent to the old {{Ambox/category}}. local status, result = pcall(formatDate, args.date, 'xg Y') if status then date = result end date = type(date) == 'string' and date local preposition = 'с' local suffix = 'года' for _, num in ipairs(nums) do local mainCat = args['cat' .. tostring(num)] or args['category' .. tostring(num)] local allCat = args['all' .. tostring(num)] mainCat = type(mainCat) == 'string' and mainCat allCat = type(allCat) == 'string' and allCat if mainCat and date and date ~= '' then local catTitle = string.format('%s %s %s %s', mainCat, preposition, date, suffix) self:addCat(0, catTitle) catTitle = getTitleObject('Категория:' .. catTitle) local status, result = pcall(formatDate, args.date) if not status then self:addCat(0, 'Википедия:Статьи с недопустимым параметром даты в шаблоне-сообщении') end elseif mainCat and (not date or date == '') then self:addCat(0, mainCat) end if allCat then self:addCat(0, allCat) end end end function MessageBox:setTemplateCategories() local args = self.args local cfg = self.cfg -- Add template categories. if cfg.templateCategory then if cfg.templateCategoryRequireName then if self.isTemplatePage then self:addCat(10, cfg.templateCategory) end elseif not self.title.isSubpage then self:addCat(10, cfg.templateCategory) end end -- Add template error categories. if cfg.templateErrorCategory then local templateErrorCategory = cfg.templateErrorCategory local templateCat, templateSort if not self.name and not self.title.isSubpage then templateCat = templateErrorCategory elseif self.isTemplatePage then local paramsToCheck = cfg.templateErrorParamsToCheck or {} local count = 0 for i, param in ipairs(paramsToCheck) do if not args[param] then count = count + 1 end end if count > 0 then templateCat = templateErrorCategory templateSort = tostring(count) end if self.categoryNums and #self.categoryNums > 0 then templateCat = templateErrorCategory templateSort = 'C' end end self:addCat(10, templateCat, templateSort) end end function MessageBox:setAllNamespaceCategories() -- Set categories for all namespaces. if self.invalidTypeError then local allSort = (self.title.namespace == 0 and 'Main:' or '') .. self.title.prefixedText self:addCat('all', 'Википедия:Необходимо исправить параметр в шаблоне-сообщении', allSort) end if self.isSubstituted then self:addCat('all', 'Википедия:Страницы с ошибочно подставленными шаблонами') end if self.isSmall then self:addCat(0, 'Википедия:Страницы с малыми шаблонами-сообщениями') end end function MessageBox:setCategories() if self.title.namespace == 0 then self:setMainspaceCategories() elseif self.title.namespace == 10 then self:setTemplateCategories() end self:setAllNamespaceCategories() end function MessageBox:renderCategories() -- Convert category tables to strings and pass them through -- [[Module:Category handler]]. return categoryHandler{ main = table.concat(self.categories[0] or {}), template = table.concat(self.categories[10] or {}), all = table.concat(self.categories.all or {}), nocat = self.args.nocat, page = self.args.page } end function MessageBox:export() local root = mw.html.create() -- Add the subst check error. if self.isSubstituted and self.name then root:tag('b') :addClass('error') :wikitext(string.format( 'Шаблон <code>%s[[Шаблон:%s|%s]]%s</code> был неккоректно подставлен.', mw.text.nowiki('{{'), self.name, self.name, mw.text.nowiki('}}') )) end -- Conditional TemplateStyles loading if self.base_templatestyles then local frame = mw.getCurrentFrame() root:wikitext(frame:extensionTag{ name = 'templatestyles', args = { src = self.base_templatestyles }, }) end -- Create the box table. local boxTable = root:tag('table') boxTable:attr('id', self.id or nil) for i, class in ipairs(self.classes or {}) do boxTable:addClass(class or nil) end boxTable :cssText(self.style or nil) :attr('role', 'presentation') if self.dataLabel1 then boxTable:attr('data-' .. self.dataLabel1, self.dataValue1) end if self.dataLabel2 then boxTable:attr('data-' .. self.dataLabel2, self.dataValue2) end if self.dataLabel3 then boxTable:attr('data-' .. self.dataLabel3, self.dataValue3) end if self.attrs then boxTable:attr(self.attrs) end -- Add the left-hand image. local row = boxTable:tag('tr') if self.imageLeft then local imageLeftCell = row:tag('td'):addClass('mbox-image') if self.imageCellDiv then -- If we are using a div, redefine imageLeftCell so that the image -- is inside it. Divs use style="width: 52px;", which limits the -- image width to 52px. If any images in a div are wider than that, -- they may overlap with the text or cause other display problems. imageLeftCell = imageLeftCell:tag('div'):css('width', '52px') end imageLeftCell:wikitext(self.imageLeft or nil) elseif self.imageEmptyCell then -- Some message boxes define an empty cell if no image is specified, and -- some don't. The old template code in templates where empty cells are -- specified gives the following hint: "No image. Cell with some width -- or padding necessary for text cell to have 100% width." row:tag('td') :addClass('mbox-empty-cell') :cssText(self.imageEmptyCellStyle or nil) end -- Add the text. local textCell = row:tag('td'):addClass('mbox-text') if self.useCollapsibleTextFields then -- The message box uses advanced text parameters that allow things to be -- collapsible. At the moment, only ambox uses this. textCell:cssText(self.textstyle or nil) local textCellDiv = textCell:tag('div') textCellDiv :addClass('mbox-text-div') :wikitext(self.issue or nil) local textsmallCellDiv = textCell:tag('div') textsmallCellDiv :addClass('mbox-textsmall-div hide-when-compact') :cssText(self.textsmallstyle) :wikitext(self.textsmall or nil) if (self.talk or self.fix) and not self.isSmall then textsmallCellDiv:tag('span') :addClass('hide-when-compact') :wikitext(self.fix and (' ' .. self.fix) or nil) :wikitext(self.talk and (' ' .. self.talk) or nil) end if self.textsmall or self.fix or self.talk then textsmallCellDiv:wikitext(self.date and (' ' .. self.date) or nil) else textCellDiv:wikitext(self.date and (' ' .. self.date) or nil) end if self.info and not self.isSmall then textsmallCellDiv :tag('span') :addClass('hide-when-compact') :wikitext(self.info and (' ' .. self.info) or nil) end if self.removalNotice then textsmallCellDiv:tag('small') :addClass('hide-when-compact') :tag('i') :wikitext(string.format(" (%s)", self.removalNotice)) end if self.shortFix then textCell:tag('div') :addClass('mbox-multiply') :tag('span') :wikitext(string.format("%s", self.shortFix)) :tag('span') :wikitext(self.date and (' ' .. self.date) or nil) end else -- Default text formatting - anything goes. textCell :cssText(self.textstyle or nil) :wikitext(self.text or nil) end -- Add the right-hand image. if self.imageRight then local imageRightCell = row:tag('td'):addClass('mbox-imageright') if self.imageCellDiv then -- If we are using a div, redefine imageRightCell so that the image -- is inside it. imageRightCell = imageRightCell:tag('div'):css('width', '52px') end imageRightCell :wikitext(self.imageRight or nil) end -- Add the below row. if self.below then boxTable:tag('tr') :tag('td') :attr('colspan', self.imageRight and '3' or '2') :addClass('mbox-text') :cssText(self.textstyle or nil) :wikitext(self.below or nil) end -- Add error message for invalid type parameters. if self.invalidTypeError then root:tag('div') :css('text-align', 'center') :wikitext(string.format( 'Этот шаблон-сообщение использует неверный параметр "type=%s", необходимо исправить.', self.type or '' )) end -- Add categories. root:wikitext(self:renderCategories() or nil) return tostring(root) end -------------------------------------------------------------------------------- -- Exports -------------------------------------------------------------------------------- local p, mt = {}, {} function p._exportClasses() -- For testing. return { MessageBox = MessageBox } end function p.main(boxType, args, cfgTables) local box = MessageBox.new(boxType, args, cfgTables or mw.loadData(CONFIG_MODULE)) box:setParameters() box:setCategories() return box:export() end function mt.__index(t, k) return function (frame) if not getArgs then getArgs = require('Module:Arguments').getArgs end return t.main(k, getArgs(frame, {trim = false, removeBlanks = false})) end end return setmetatable(p, mt) f2539b657a9cdadde7c0dd5ad270d3095b2bdd54 Шаблон:Очистить кэш 10 94 185 2024-03-27T11:58:48Z wikipedia:ru>Stjn 0 не помещать на все страницы ежедневную очистку кэша wikitext text/x-wiki <!-- Класс purgelink и атрибут data-pagename используются в [[MediaWiki:Common.js]], чтобы очищать кэш без перехода на отдельную страницу --><span class="noprint purgelink" {{#if: {{{2|}}} | data-pagename="{{{2}}}" }}>{{выполнить скрипт|purgeLink}}[[Special:Purge/{{#if: {{{2|}}} | {{{2}}} | {{FULLPAGENAME}} }}|{{#if: {{{1|}}} | {{{1}}} | Очистить кэш }}]]</span>{{#ifeq: {{NAMESPACE}}{{{nocat|}}} | {{ns:10}} <!-- Шаблон --> | {{очищать кэш|ежедневно}} }}<noinclude>{{doc}}</noinclude> be6695060ca61d2125386d02d3a19109c0e7c27b Модуль:Yesno 828 12 21 2024-03-30T22:30:54Z wikipedia:ru>Stjn 0 кириллическая у из-за невозможности различить от латинской Scribunto text/plain -- Function allowing for consistent treatment of boolean-like wikitext input. -- It works similarly to the template {{yesno}}. return function (val, default) -- If your wiki uses non-ascii characters for any of "yes", "no", etc., you -- should replace "val:lower()" with "mw.ustring.lower(val)" in the -- following line. val = type(val) == 'string' and val:lower() or val if val == nil then return nil elseif val == true or val == 'yes' or val == 'y' or val == 'true' or val == 't' or val == 'да' or val == 'д' -- кириллица or val == 'у' or val == '+' or tonumber(val) == 1 then return true elseif val == false or val == 'no' or val == 'n' or val == 'false' or val == 'f' or val == 'нет' or val == 'н' or val == '-' or tonumber(val) == 0 then return false else return default end end ae94e12a838e770797317ed07b57b330ffeb7658 Шаблон:Yesno-yes 10 66 129 2024-04-05T13:04:36Z wikipedia:ru>Stjn 0 подстановка wikitext text/x-wiki {{safesubst:<noinclude />yesno|{{{1}}}|yes={{{yes|yes}}}|no={{{no|no}}}|blank={{{blank|yes}}}|¬={{{¬|yes}}}|def={{{def|yes}}}}}<noinclude> {{doc}} </noinclude> 3792ff694708f98102e3a6d556abe73bedc29069 Шаблон:Выполнить скрипт 10 100 197 2024-04-07T13:34:28Z wikipedia:ru>Stjn 0 отключение старой схемы wikitext text/x-wiki {{#switch: {{{1|}}} | = | mainPage = [[Категория:Википедия:Заглавная страница|{{NAMESPACENUMBER}}]] | #default = {{#ifexist: Категория:Википедия:Страницы с гаджетом по требованию {{{1}}} | [[Категория:Википедия:Страницы с гаджетом по требованию {{{1}}}|{{NAMESPACENUMBER}}]] }} }}<noinclude> {{doc}} </noinclude> 6979ea0342067dc76b9adcb9a5e072207c2c5a63 Шаблон:Старый-новый стиль,примечание 10 104 205 2024-04-13T19:25:38Z wikipedia:ru>Mikhail Ryazanov 0 [[Календарная дата#Форматы записи даты]], стилевые правки wikitext text/x-wiki В случае, если дата рождения/смерти в источниках приведена по [[Юлианский календарь|старому стилю]], рекомендуется указывать её по новому стилю, а после указать в скобках отличающуюся часть даты по старому стилю. Например, * «13.05.1801 (1)» будет отображено как [[13 мая|1 (13) мая]] [[1801 год|1801]]; * «12.06.1801 (31.05)» будет отображено как 31 мая ([[12 июня]]) [[1801 год|1801]]; * «12.01.1802 (31.12.1801)» будет отображено как 31 декабря 1801 ([[12 января]] [[1802 год|1802]]). При этом в статью будут автоматически подставлены категории даты рождения/смерти по ''новому'' стилю. Учтите, что разница между датами нового и старого стиля составляет 13 дней в XX и XXI веках, 12 дней в XIX веке, 11 дней в XVIII веке, 10 дней в XVII и XVI веках (начиная с 5 (15) октября 1582 года).<noinclude>{{doc-inline}}Шаблон предназначен для подстановки в качестве примечания к полям «дата рождения», «дата смерти» для страниц документации шаблонов-карточек типа «Персона». Параметров не принимает. Вызов: {{tl|Старый-новый стиль,примечание}} {{doc-end}} [[Категория:Википедия:Шаблоны, встраиваемые в шаблоны-карточки:Личности]] </noinclude> 7f8754eb5c2401671df545a1cd8b315f66f86463 Шаблон:Replace 10 37 71 2024-04-14T07:24:11Z wikipedia:ru>Stjn 0 обновление аналогично английскому шаблону wikitext text/x-wiki {{safesubst:<noinclude />#invoke:String|replace|source={{{1}}}|{{{2}}}|{{{3}}}|plain={{{plain|true}}}|count={{{count|}}}}}<noinclude> {{doc}} </noinclude> 7752c3c70ae8c46a89a0808aa282956866dbba5b Шаблон:Wikidata gender switch 10 49 95 2024-04-28T17:08:48Z wikipedia:ru>Dima st bk 0 + lc по запросу на СО wikitext text/x-wiki {{#switch: {{wikidata|p21|{{lc:{{delink|{{{1|}}}}}}}|plain=true|from={{{from|}}}}} | 1 | f | fem | female | feminine | ж | жен | женский | женский пол | транс-женщина | Q6581072 | Q1052281 | Q43445 = {{{2}}} | m | male | masculine | м | муж | мужской | мужской пол | транс-мужчина | Q6581097 | Q2449503 | Q44148 = {{{3}}} | #default = {{#if:{{{4|}}}|{{{4}}}|{{{3}}}}} }}<noinclude> {{doc}} </noinclude> 24ccdd5a8702a7028386e9b887d3acf1b5f81c34 Шаблон:Действия для страницы/styles.css 10 86 169 2024-05-02T17:22:30Z wikipedia:ru>Stjn 0 fix text text/plain .ts-tlinks-tlinks { font-weight: normal; float: right; line-height: inherit; } .ts-tlinks-tlinks .mw-editsection-divider { display: inline; } /* [[Категория:Шаблоны:Подстраницы CSS]] */ a003e896d263c29e66d2246b210e5d73e577ea46 Шаблон:Действия для страницы 10 85 167 2024-05-02T17:24:27Z wikipedia:ru>Stjn 0 никаких пиксельных fontsize wikitext text/x-wiki <templatestyles src="Шаблон:Действия для страницы/styles.css" /><div style="{{#ifeq: {{yesno-yes|{{{right|}}}}} | yes || float:none; }}" class="ts-tlinks-tlinks mw-editsection-like plainlinks"><span class="mw-editsection-bracket">[</span><!-- -->{{join|separator=<span class="mw-editsection-divider"> &amp;#124; </span> |1={{#ifexist: {{#rel2abs: {{{lc|}}} }} | {{#ifeq: {{{dislooklink|{{{noview|}}}}}} | yes || [[{{{lc}}}|просмотр]] }} }} |2={{#ifexist: {{#rel2abs: {{{lc|}}} }} | [[Special:EditPage/{{#rel2abs: {{{lc}}} }}|править]] }} |3={{#ifexist: {{#rel2abs: {{{lc|}}} }} | {{#ifeq: {{{dishistlink|{{{nohistory|}}}}}} | yes || [[Special:PageHistory/{{#rel2abs: {{{lc}}} }}|история]] }} }} |4={{#ifexist: {{#rel2abs: {{{lc|}}} }} | | [{{fullurl:{{#rel2abs: {{{lc}}} }}|action=edit&redlink=1}} создать] }} |5={{#ifeq: {{{diswatchlink|{{{nowatch|}}}}}} | yes || [{{fullurl:{{#rel2abs: {{{lc}}} }}|action=watch}} следить] }} |6={{#ifeq: {{{disupdlink|{{{noupdate|}}}}}} | yes || {{очистить кэш|обновить|nocat=1}}</span> }} }}<span class="mw-editsection-bracket">]</span></div><noinclude> {{doc}} </noinclude> 9ee2c9eed92e2ecc9377a7b9486ad8bc214a83d4 Модуль:Wikidata/Medals 828 68 133 2024-05-04T17:24:40Z wikipedia:ru>Putnik 0 импорт списка дубликатов из [[az:Modul:Wikidata/Medals]] Scribunto text/plain local WDS = require( 'Module:WikidataSelectors' ) local moduleDate = require( 'Module:Wikidata/date' ) local awardsOrder = mw.ext.data.get( "Wikidata/awards order.tab" ) local p = {} local config = { --Hide award with key QID if there is a reward with value QID absorption = { Q16675272 = 'Q654471', Q16481808 = 'Q8706404', Q1948730 = 'Q178473', Q1980962 = 'Q208167', Q2032399 = 'Q2046996', Q102183407 = 'Q103819965', Q1262166 = 'Q80589', Q749849 = 'Q1358055', Q4287121 = 'Q4137462', } } --Get string with dates from qualifiers table local function datesFromQualifier( context, options, qualifierId ) local dates = {} local qualifiers = options.qualifiers[ qualifierId ] if qualifiers then for _, qualifier in pairs( qualifiers ) do if qualifier.datavalue then local dateValue = moduleDate.formatDate( context, options, qualifier.datavalue.value ) if dateValue then table.insert( dates, dateValue ) end end end end return table.concat( dates, ', ' ) end --Property function for [[d:Property:P166]] function p.formatProperty( context, options ) if ( not context ) then error( 'context not specified' ); end; if ( not options ) then error( 'options not specified' ); end; if ( not options.entityId ) then error( 'options.entityId missing' ); end; local claims; if options.property then -- TODO: Почему тут может не быть property? claims = context.selectClaims( options, options.property ); end if claims == nil then return '' --TODO error? end -- Обход всех заявлений утверждения и с накоплением оформленых -- предпочтительных заявлений в таблице. local formattedData = {} for i, claim in ipairs( claims ) do if ( claim.mainsnak and claim.mainsnak and claim.mainsnak.datavalue and claim.mainsnak.datavalue.type == 'wikibase-entityid' ) then local valueId = claim.mainsnak.datavalue.value.id local formattedStatement = context.formatStatement( options, claim ) -- здесь может вернуться либо оформленный текст заявления, либо строка ошибки, либо nil if ( formattedStatement and formattedStatement ~= '' ) then formattedStatement = '<span class="wikidata-claim" data-wikidata-property-id="' .. string.upper( options.property ) .. '" data-wikidata-claim-id="' .. claim.id .. '">' .. formattedStatement .. '</span>' table.insert( formattedData, { id = valueId, html = formattedStatement, } ) end end end -- Удаление дублей (медаль + звание -> звание) for i, awardData in ipairs( formattedData ) do local isAbsorptionFound = false if config.absorption[ awardData.id ] then local absorptionAwardId = config.absorption[ awardData.id ] for _, absorptionAwardData in ipairs( formattedData ) do if absorptionAwardData.id == absorptionAwardId then isAbsorptionFound = true break end end end if isAbsorptionFound then table.remove( formattedData, i ) end end -- Сортировка медалей по старшинству local orderedData = {} local lastValue; if ( type (awardsOrder) == 'table' ) then -- Если не отсохла stuctured data for i, awardFields in ipairs( awardsOrder.data ) do local awardOrder = awardFields[ 1 ] if awardOrder == '-' then -- separator if lastValue ~= '-' then table.insert( orderedData, '<br>' ) lastHeight = nil end else for k, awardData in ipairs( formattedData ) do if awardOrder == awardData.id and not awardData.used then table.insert( orderedData, awardData.html ) formattedData[ k ].used = true end end end end end for i, awardData in ipairs( formattedData ) do if not awardData.used then table.insert( orderedData, awardData.html ) end end local lastHeight for i, awardHtml in ipairs( orderedData ) do local height = mw.ustring.match( awardHtml, 'x%d+px' ) if height and lastHeight and height ~= lastHeight then table.insert( orderedData, i, '<br>' ) end lastHeight = height end -- создание текстовой строки со списком оформленых заявлений из таблицы local out = mw.text.listToText( orderedData, options.separator, options.conjunction ) if out ~= '' then if options.before then out = options.before .. out end if options.after then out = out .. options.after end end return out end local function getImageFromProperty( entityId, propertyId ) local imageClaims = WDS.load( entityId, propertyId ) if imageClaims and #imageClaims > 0 then for _, claim in ipairs( imageClaims ) do if claim.type == 'statement' and claim.mainsnak.snaktype == 'value' then return claim.mainsnak.datavalue.value end end end return nil end -- Получение изображения (планки или иконки) и его размера function p.getImageFromEntity( entityId, actualDate ) if type( entityId ) ~= "string" then entityId = entityId.id end local image = nil local size = 'x17px' local border = false -- получение изображения планки из элемента image = getImageFromProperty( entityId, 'P2425' ) if image then border = true end -- получение иконки из элемента if not image then image = getImageFromProperty( entityId, 'P2910' ) if image then size = '40x40px' end end return image, size, border end --Value function for [[d:Property:P166]] function p.formatValue( context, options, statement ) local entityId = statement.id if not entityId then return statement end local label = mw.wikibase.getLabel( entityId ) local image, size, border = p.getImageFromEntity( entityId ) local recipientCategory = '' if not options.nocat and options.nocat ~= '' then recipientCategory = context.extractCategory( { category = 'P7084[P4224:Q24571879]' }, entityId ) if recipientCategory == '' then recipientCategory = context.extractCategory( { category = 'P2517' }, entityId ) end end local dates = '' if options.qualifiers then local startDates = {} dates = datesFromQualifier( context, options, 'P580' ) if dates ~= '' then local endDates = datesFromQualifier( context, options, 'P582' ) if endDates and endDates ~= '' then dates = dates .. ' — ' .. endDates end else dates = datesFromQualifier( context, options, 'P585' ) end if options.qualifiers.P27 then mw.log('>>>>>>>>>>>>>') for _, claim in ipairs( options.qualifiers.P27 ) do if claim and claim.datavalue and claim.datavalue.value and claim.datavalue.value.id then local categoryOptions = { category = 'P7084[P27:' .. claim.datavalue.value.id .. ']' } recipientCategory = recipientCategory .. context.extractCategory( categoryOptions, entityId ) end end end end -- получение ссылки по идентификатору и вывод планки if image then local link = mw.wikibase.getSitelink( entityId ) local out = '[[File:' .. image if border == true then out = out .. '|border' end out = out .. '|' .. size .. '|link=' -- получение ссылки из родительского элемента -- для степеней обычно только одна общая статья if not link then local partOfClaims = WDS.load( entityId, 'P361' ) -- часть от if not partOfClaims or #partOfClaims == 0 then partOfClaims = WDS.load( entityId, 'P279' ) -- подкласс от end if partOfClaims and #partOfClaims > 0 then for _, claim in ipairs( partOfClaims ) do if claim.type == 'statement' and claim.mainsnak.snaktype == 'value' then link = mw.wikibase.getSitelink( claim.mainsnak.datavalue.value.id ) if link then break end end end end end if link then out = out .. link else out = out .. 'd:' .. entityId end if label then out = out .. '|' .. label end out = out .. ']]' out = out .. recipientCategory return out end local out = context.formatValueDefault( context, options, statement ) if out and out ~= '' then if dates ~= '' then out = out .. ' (' .. dates .. ')' end return '<span style="display:inline-block; text-align:left>' .. out .. recipientCategory .. '</span>' end return '' end --Table for documentation function p.renderDoc() local out = {} for i, awardFields in ipairs( awardsOrder.data ) do local awardId = awardFields[ 1 ] local link = '[[d:' .. awardId .. '|' .. awardId .. ']]' if i == 351 then -- limits table.insert( out, '| … || … || … || … || …' ) elseif i > 351 and i < #awardsOrder.data then -- do nothing elseif awardId == '-' then -- separator table.insert( out, '|' .. i .. '|| colspan="3" | ----' ) else local image, size, border = p.getImageFromEntity( awardId ) if image then image = '[[File:' .. image if border == true then image = image .. '|border' end image = image .. '|' .. size .. ']]' else image = '' end local label = mw.wikibase.getLabel( awardId ) or '' local article = mw.wikibase.getSitelink( awardId ) if article then if label == '' then label = article end label = '[[' .. article .. '|' .. label .. ']]' end local countryStatements = mw.wikibase.getBestStatements( awardId, 'P17' ) local countries = {} if countryStatements then for _, statement in ipairs( countryStatements ) do if statement.mainsnak.datavalue and statement.mainsnak.datavalue.type == 'wikibase-entityid' then local countryId = statement.mainsnak.datavalue.value.id table.insert( countries, mw.wikibase.getLabel( countryId ) ) end end end table.insert( out, '|' .. i .. '||' .. link .. '||' .. image .. '||' .. label .. '||' .. table.concat( countries, ', ' ) ) end end return '{| class="wikitable"\n' .. '! # !! Элемент !! Планка !! Название !! Государство\n|-\n' .. table.concat( out, '\n|-\n' ) .. '\n|}' end return p 4de64e0e2181e8a4487f3e18da893fca9f92660d Шаблон:OnLua 10 98 193 2024-05-07T19:08:37Z wikipedia:ru>MBH 0 MBH переименовал страницу [[Шаблон:OnLua]] в [[Шаблон:Lua]] wikitext text/x-wiki #перенаправление [[Шаблон:Lua]] b72371e7ae22239863c474a78238171c2bd94c7e Шаблон:Lua 10 105 207 2024-05-07T19:08:37Z wikipedia:ru>MBH 0 MBH переименовал страницу [[Шаблон:OnLua]] в [[Шаблон:Lua]] wikitext text/x-wiki <includeonly>{{ombox | small = yes | style = width:23em; | image = [[Файл:Lua-logo-nolabel.svg|40px|alt=|link=]] | text = {{replace|Этот шаблон {{#if: {{{partly|}}} | частично }} реализован на основе [[Lua]]{{#if:{{{module2|}}}{{{tech2|}}}|&#58;<br><ul><li>}}{{#if:{{{1|}}}{{{tech|}}}|&#32;с использованием {{{tech|{{#if:{{{2|}}}|функции <code>{{#if:{{{line|}}}|[[Module:{{{1}}}#L-{{{line}}}|{{{2}}}()]]|[[{{{funcref|Module:{{{1}}}#{{{2}}}}}}|{{{2}}}()]]}}</code> из&#32;}}{{#if:{{{1|}}}|модуля [[Module:{{{1}}}|{{{1}}}]]}}}}};}}<!-- -->{{#invoke:Transclude|npc|OnLua/Строка| module= |function= |tech= |line= }}.|;.|.}}{{#if:{{{module2|}}}{{{tech2|}}}|</ul>}} {{#if:{{{1|}}}{{{tech|}}}{{{module1|}}}{{{tech1|}}}||<div class="error"><small>'''Не указано название использующегося модуля!'''</small></div>}} }}{{#ifeq:{{SUBPAGENAME}}|{{{doc|doc}}}||{{#if:{{{nocat|}}}||[[Категория:Шаблоны, использующие Scribunto]]{{#if:{{{1|}}}{{{tech|}}}{{{module1|}}}{{{tech1|}}}||[[Категория:Шаблоны, использующие Lua, без указания модуля]]}}}}}}</includeonly><noinclude>{{doc}}</noinclude> f1fdaa87edb15d61e23e98f6e25d171a975e10eb Шаблон:OnLua/Строка 10 101 199 2024-05-07T19:08:38Z wikipedia:ru>MBH 0 MBH переименовал страницу [[Шаблон:OnLua/Строка]] в [[Шаблон:Lua/Строка]] wikitext text/x-wiki #перенаправление [[Шаблон:Lua/Строка]] d7f869ccc7a7efc800399fce32bc75e0f91066de Шаблон:Lua/Строка 10 112 221 2024-05-07T19:08:38Z wikipedia:ru>MBH 0 MBH переименовал страницу [[Шаблон:OnLua/Строка]] в [[Шаблон:Lua/Строка]] wikitext text/x-wiki <includeonly>{{#if: {{{module|}}}{{{tech|}}} | <li>с использованием {{#if: {{{tech|}}} | {{{tech}}} | {{#if: {{{function|}}} | {{#if: {{{module|}}} | функции <code>{{#if: {{{line|}}} | [{{fullurl: Module:{{{module}}}|action=edit}}#mw-ce-l{{{line}}} {{{function}}}()] | [[{{{funcref|Module:{{{module}}}#{{{function}}}}}} | {{{function}}}()]]}}</code> из&#32;}}}}{{#if: {{{module|}}} | модуля [[Module:{{{module}}} | {{{module}}}]]}}}};}}</includeonly><noinclude>[[Категория:Шаблоны:Подстраницы шаблонов]]</noinclude> 5a35837338c2daee2d240a8e5335e8fec8e7d87e Шаблон:Wikidata/p569 10 46 89 2024-05-08T19:10:13Z wikipedia:ru>Dima st bk 0 |suppressAge={{{suppress age|}}} с викиданных wikitext text/x-wiki {{#switch:{{{1|}}}|-=|={{#invoke:Wikidata|formatStatements|property=p569|claim-module=Wikidata/date|claim-function=formatDateOfBirthClaim|nocat={{{nocat|}}}{{NAMESPACE}}|suppressAge={{{suppress age|}}}}}|{{#invoke:Infocards|dateOfBirth|{{{1|}}}|{{{2|}}}|suppressAge={{wikidata|P570|plain=true}}{{{suppress age|}}}|nocat={{{nocat|}}}{{NAMESPACE}}}}}}<noinclude>{{doc}}</noinclude> 9643ab18fcd322831b72e38658b58c6b94a914e2 Шаблон:Установлена проверка на неизвестные параметры 10 95 187 2024-05-10T14:11:21Z wikipedia:ru>Abiyoyo 0 категория для шаблонов отдельно, для самих категорий отдельно wikitext text/x-wiki {{ombox |name = Установлена проверка на неизвестные параметры |text = В этом шаблоне установлена [[Модуль:Check for unknown parameters|проверка на неизвестные параметры]], добавляющая страницы в {{c|{{#if:{{{категория|}}}|{{{категория|}}}|Страницы с неизвестными параметрами шаблона {{ROOTPAGENAME}}}}|В}}. |type = notice }}<includeonly>{{no-doc|[[Категория:Шаблоны с установленной проверкой на неизвестные параметры]]{{#ifexist: Категория:{{#if:{{{категория|}}}|{{{категория|}}}|Страницы с неизвестными параметрами шаблона {{ROOTPAGENAME}}}} || [[Категория:Шаблоны с установленной проверкой на неизвестные параметры и несуществующей категорией]] }}|nocat={{{nocat|}}}}}</includeonly><noinclude>{{doc-inline}} См. [[Модуль:Check for unknown parameters]] и [[:Категория:Википедия:Неизвестные параметры шаблонов]]. Добавляет {{Категория с размером|Шаблоны с установленной проверкой на неизвестные параметры и несуществующей категорией}}. [[Категория:Шаблоны:Предупреждения]] [[Категория:Шаблоны:Для документирования шаблонов]] {{doc-end}} </noinclude> cd47e06eec53b65393adba1f3143d6cd3d6cc54c Модуль:Wikidata/date 828 59 115 2024-06-10T15:24:01Z wikipedia:ru>Stjn 0 необъявленная глобальная переменная Scribunto text/plain --settings local nowLabel = 'наст.&nbsp;время' local moduleDates = require( "Module:Dates" ) local moduleWikidata = require( "Module:Wikidata" ) local dateCat = require("Module:Infocards/dateCat") -- FIXME: undeclared global variable, used 3 times local infoclass local function deepcopy(orig) local orig_type = type(orig) local copy if orig_type == 'table' then copy = {} for orig_key, orig_value in next, orig, nil do copy[deepcopy(orig_key)] = deepcopy(orig_value) end setmetatable(copy, deepcopy(getmetatable(orig))) else -- number, string, boolean, etc copy = orig end return copy end local function ageImpl ( bStructure, bPrecision, dStructure, dPrecision ) if ( not bStructure or not dStructure or bPrecision < 10 or dPrecision < 10 ) then return nil end local shift = 0 if ( bStructure.year < 0 and dStructure.year > 0 ) then shift = -1 end if ( bPrecision == 10 or dPrecision == 10 ) then if ( bStructure.month < dStructure.month ) then return dStructure.year - bStructure.year + shift end if ( bStructure.month == dStructure.month ) then return nil end if ( bStructure.month > dStructure.month ) then return dStructure.year - bStructure.year - 1 + shift end end if ( bStructure.month < dStructure.month ) then return dStructure.year - bStructure.year + shift end if ( bStructure.month == dStructure.month ) then if ( bStructure.day <= dStructure.day ) then return dStructure.year - bStructure.year + shift else return dStructure.year - bStructure.year - 1 + shift end end if ( bStructure.month > dStructure.month ) then return dStructure.year - bStructure.year - 1 + shift end return nil end -- accepts table of time+precision values local function ageCurrent ( bTable ) local possibleAge = "NYA" -- it means "Not Yet Assigned", not what you imagined! for bKey, bValue in pairs(bTable) do if ( bValue.unknown ) then return nil end local bStructure = bValue.structure local bPrecision = bValue.precision local dStructure = os.date( "*t" ) local calculatedAge = ageImpl ( bStructure, bPrecision, dStructure, 11 ) if ( possibleAge == "NYA" ) then possibleAge = calculatedAge else if ( possibleAge ~= calculatedAge ) then possibleAge = nil end end end return possibleAge end -- accepts tables of time+precision values local function age ( bTable, dTable ) local possibleAge = "NYA" -- it means "Not Yet Assigned", not what you imagined! for bKey, bValue in pairs( bTable ) do if ( bValue.unknown ) then return nil end local bStructure = bValue.structure local bPrecision = bValue.precision for dKey, dValue in pairs( dTable ) do if ( dValue.unknown ) then return nil end local dStructure = dValue.structure local dPrecision = dValue.precision if ( bValue.calendar == 'julian' and dValue.calendar == 'gregorian' ) then -- to calculate age, need to adjust bStructure to gregorian calendar local shift = math.floor(bStructure.year/100-2) - math.floor(bStructure.year/400) -- TODO: re-implement this properly bStructure.day = bStructure.day + shift end local calculatedAge = ageImpl ( bStructure, bPrecision, dStructure, dPrecision ) if ( possibleAge == "NYA" ) then possibleAge = calculatedAge else if ( possibleAge ~= calculatedAge ) then possibleAge = nil end end end end return possibleAge end local function parseISO8601Date(str) local pattern = "(%-?%d+)%-(%d+)%-(%d+)T" local Y, M, D = mw.ustring.match( str, pattern ) return tonumber(Y), tonumber(M), tonumber(D) end local function parseISO8601Time(str) local pattern = "T(%d+):(%d+):(%d+)%Z" local H, M, S = mw.ustring.match( str, pattern) return tonumber(H), tonumber(M), tonumber(S) end local function parseISO8601Offset(str) if str:sub(-1)=="Z" then return 0,0 end -- ends with Z, Zulu time -- matches ±hh:mm, ±hhmm or ±hh; else returns nils local pattern = "([-+])(%d%d):?(%d?%d?)$" local sign, oh, om = mw.ustring.match( str, pattern) sign, oh, om = sign or "+", oh or "00", om or "00" return tonumber(sign .. oh), tonumber(sign .. om) end local function parseISO8601(str) if 'table' == type(str) then if str.args and str.args[1] then str = '' .. str.args[1] else return 'unknown argument type: ' .. type( str ) .. ': ' .. table.tostring( str ) end end local Y,M,D = parseISO8601Date(str) local h,m,s = parseISO8601Time(str) local oh,om = parseISO8601Offset(str) if not Y or not M or not D or not h or not m or not s or not oh or not om then return nil end return tonumber(os.time({year=Y, month=M, day=D, hour=(h+oh), min=(m+om), sec=s})) end local function parseClaim ( claim ) if ( claim.mainsnak.snaktype == "value" ) then local timeISO8601 = string.gsub( string.gsub( tostring( claim.mainsnak.datavalue.value.time ), '-00%-', '-01-' ), '-00T', '-01T' ) local unixtime = parseISO8601( timeISO8601 ) local structure = os.date("*t", unixtime) local precision = tonumber( claim.mainsnak.datavalue.value.precision ) local calendarmodel = 'gregorian' if (mw.ustring.find(claim.mainsnak.datavalue.value.calendarmodel, 'Q1985786', 1, true)) then calendarmodel = 'julian' end local item = { structure=structure, precision=precision, calendar = calendarmodel } return item elseif ( claim.mainsnak.snaktype == "novalue" ) then -- novalue return { unknown="novalue" } else --unknown return { unknown="unknown" } end end -- returns table of time+precision values for specified property local function parseProperty ( context, options, propertyId ) if ( not context ) then error( 'context not specified'); end if ( not options ) then error( 'options not specified'); end if ( not options.entity ) then error( 'options.entity is missing'); end if ( not propertyId ) then error( 'propertyId not specified'); end local claims = context.selectClaims( options, propertyId ) if not claims then return nil end local result = {} for key, claim in pairs( claims ) do table.insert ( result, parseClaim( claim ) ) end return result end -- проверка на совпадающие даты с разной моделью календаря local function checkDupDates( t ) if #t > 1 then local removed = false local j = 1 -- проверка на совпадающие даты с разной моделью календаря while (j <= #t) do local i = 1 while (i <= #t) do if i ~= j then if (os.time(t[j].structure) == os.time(t[i].structure)) then if ((t[j].calendarmodel == 'gregorian') and (t[i].calendarmodel == 'julian')) then removed = true break else table.remove(t, i) end else i = i + 1 end else i = i + 1 end end if removed then removed = false table.remove(t, j) else j = j+1 end end end end -- returns first qualifier of specified propertyId local function getQualifierWithDataValue( statement, qualifierPropertyId ) if ( statement.qualifiers and statement.qualifiers[qualifierPropertyId] ) then local qualifiers = statement.qualifiers[qualifierPropertyId] for _, qualifier in ipairs( qualifiers ) do if (qualifier.datavalue) then return qualifier end end end return nil end local p = {} local function formatDecade( time, categoryNamePrefix ) local bce = '' local year if time.year < 0 then bce = ' до н. э.' year = math.floor( math.abs( time.year ) / 10 ) * 10 else year = math.floor( time.year / 10 ) * 10 end local unit = '-е' if isGenitive then unit = '-х' end local value = '' .. year .. unit .. bce if categoryNamePrefix then return value .. '[[Category:' .. categoryNamePrefix .. ' в ' .. year .. '-е годы' .. bce .. ']]' end return value end local function formatCentury( time, categoryNamePrefix, isGenitive ) local moduleRoman = require( 'Module:RomanNumber' ) local bce = '' local century if time.year < 0 then bce = ' до н. э.' century = math.floor( ( math.abs( time.year ) - 1 ) / 100 ) + 1 else century = math.floor( ( time.year - 1 ) / 100 ) + 1 end local unit = 'век' if isGenitive then unit = 'века' end local infix = ' в ' if century == 2 then infix = ' во ' end if moduleRoman then century = moduleRoman.toRomanNumber( century ) end local value = '[[' .. century .. ' век' .. bce .. '|' .. century .. ' ' .. unit .. bce .. ']]' if categoryNamePrefix then return value .. '[[Category:' .. categoryNamePrefix .. infix .. century .. ' веке' .. bce .. ']]' end return value end local function formatMillenium( time, categoryNamePrefix, isGenitive ) local bce = '' local millenium if time.year < 0 then bce = ' до н. э.' millenium = math.floor( ( math.abs( time.year ) - 1 ) / 1000 ) + 1 else millenium = math.floor( ( time.year - 1 ) / 1000 ) + 1 end local unit = '-е тысячелетие' if isGenitive then unit = '-го тысячелетия' end local value = '[[' .. millenium .. '-е тысячелетие' .. bce .. '|' .. millenium .. unit .. bce .. ']]' if categoryNamePrefix then local infix = ' в ' if millenium == 2 then infix = ' во ' end return value .. '[[Category:' .. categoryNamePrefix .. infix .. millenium .. '-м тысячелетии' .. bce .. ']]' else return value end end local function formatDateImpl( value, options, microformatClass, categoryPrefix, leftBracket, rightBracket, nolinks, isGenitive ) if ( not value ) then error( 'value not specified'); end if ( not options ) then error( 'options not specified'); end -- The calendar model used for saving the data is always the proleptic Gregorian calendar according to ISO 8601. local timeISO8601 = string.gsub( string.gsub( tostring( value.time ), '-00%-', '-01-' ), '-00T', '-01T' ) local unixtime = parseISO8601( timeISO8601 ) if not unixtime then return '' end local structure = os.date("*t", unixtime) local precision = tonumber( value.precision ) if precision <= 6 then return formatMillenium( structure, categoryPrefix, isGenitive ) end if precision == 7 then return formatCentury( structure, categoryPrefix, isGenitive ) end if precision == 8 then return formatDecade( structure, categoryPrefix, isGenitive ) end if precision == 9 then local tCopy = deepcopy( structure ) tCopy.day = nil tCopy.month = nil return moduleDates.formatWikiImpl( tCopy, tCopy, infoclass, categoryPrefix, leftBracket, rightBracket, nolinks ) end -- year and month only if precision == 10 then local tCopy = deepcopy( structure ) tCopy.day = nil return moduleDates.formatWikiImpl( tCopy, tCopy, infoclass, categoryPrefix, leftBracket, rightBracket, nolinks ) end local calendarmodel = 'gregorian' if (mw.ustring.find(value.calendarmodel, 'Q1985786', 1, true)) then calendarmodel = 'julian' end if (calendarmodel == 'gregorian') then return moduleDates.formatWikiImpl( structure, structure, microformatClass, categoryPrefix, leftBracket, rightBracket, nolinks ) else return p.formatAsJulian( timeISO8601, infoclass, categoryPrefix, leftBracket, rightBracket, nolinks ) end end local function formatApproximateDateClaim( context, options, statement, unknownDateCategory ) if ( not context ) then error( 'context not specified'); end if ( not options ) then error( 'options not specified'); end if ( not options.entity ) then error( 'options.entity is missing'); end if ( not statement ) then error( 'statement not specified'); end if options.nocat then unknownDateCategory = "" end local qNotSoonerThan = getQualifierWithDataValue( statement, 'P1319' ) local qNotLaterThan = getQualifierWithDataValue( statement, 'P1326' ) if ( qNotSoonerThan or qNotLaterThan ) then local results = {} if ( qNotSoonerThan ) then local formattedDate = formatDateImpl( qNotSoonerThan.datavalue.value, {}, nil, nil, options.leftBracket, options.rightBracket, options.nolinks, true ) local value = 'не&nbsp;ранее&nbsp;' .. context.wrapSnak( formattedDate, qNotSoonerThan.hash ) table.insert( results, context.wrapQualifier( value, 'P1319' ) ) end if ( qNotLaterThan ) then local formattedDate = formatDateImpl( qNotLaterThan.datavalue.value, {}, nil, nil, options.leftBracket, options.rightBracket, options.nolinks, true ) local value = 'не&nbsp;позднее&nbsp;' .. context.wrapSnak( formattedDate, qNotLaterThan.hash ) table.insert( results, context.wrapQualifier( value, 'P1326' ) ) end return mw.text.listToText( results, ' и ' , ' и ' ) .. unknownDateCategory .. context.formatRefs( options, statement ) end return nil end function p.formatDateOfBirthClaim( context, options, statement ) local value = formatApproximateDateClaim( context, options, statement, dateCat.categoryUnknownBirthDate ) if value then return value end options['conjunction'] = '&#32;или&#32;' options['value-module'] = 'Wikidata/date' options['value-function'] = 'formatBirthDate' options.i18n.somevalue = '\'\'неизвестно\'\'' .. dateCat.categoryUnknownBirthDate local circumstances = context.getSourcingCircumstances( statement ) for _, itemId in ipairs( circumstances ) do if itemId == 'Q5727902' then options.isGenitive = true break end end local result = context.formatStatementDefault( context, options, statement ) local bTable = { parseClaim( statement ) } local dTable = parseProperty ( context, options, 'P570' ) if ( bTable and not dTable ) then local age = ageCurrent( bTable ) if ( age ) then if ( options.suppressAge == nil or options.suppressAge == '' ) then result = result .. ' <span style="white-space:nowrap;">(' .. age .. ' ' .. mw.language.new( 'ru' ):plural( age, 'год', 'года', 'лет') .. ')</span>' end if ( not options.nocat ) then if ( age > 115 ) then result = result .. dateCat.categoryBigCurrentAge elseif (age >= 0) then result = result .. dateCat.categoryBiographiesOfLivingPersons else result = result .. dateCat.categoryNegativeAge end end end end return result end function p.formatDateOfDeathClaim( context, options, statement ) local value = formatApproximateDateClaim( context, options, statement, dateCat.categoryUnknownDeathDate ) if value then return value end options['conjunction'] = '&#32;или&#32;' options['value-module'] = 'Wikidata/date' options['value-function'] = 'formatDeathDate' options.i18n.somevalue = '\'\'неизвестно\'\'' .. dateCat.categoryUnknownDeathDate local circumstances = context.getSourcingCircumstances( statement ) for _, itemId in ipairs( circumstances ) do if itemId == 'Q5727902' then options.isGenitive = true break end end local result = context.formatStatementDefault( context, options, statement ) local bTable = parseProperty ( context, options, 'P569' ) local dTable = { parseClaim( statement ) } if ( bTable and dTable ) then local age = age( bTable, dTable ) if ( age ) then if ( options.suppressAge == nil or options.suppressAge == '' ) then result = result .. ' <span style="white-space:nowrap;">(' .. age .. ' ' .. mw.language.new( 'ru' ):plural( age, 'год', 'года', 'лет') .. ')</span>' end if ( not options.nocat and age < 0) then result = result .. dateCat.categoryNegativeAge end end -- returns category to recently deceased persons local unixAvailable, unixDateOfDeath = pcall(function() local r = os.time(dTable[1].structure) if ( r ~= os.time() ) then return r end error() end) if ( unixAvailable and os.time() - unixDateOfDeath < 31536000 and not options.nocat ) then result = result .. dateCat.categoryRecentlyDeceased end end return result end -- Reentry point for Wikidata Snak formatting function p.formatBirthDate( context, options, value ) if ( not context ) then error( 'context not specified'); end if ( not options ) then error( 'options not specified'); end if ( not value ) then error( 'value not specified'); end local microformatClass = nil if options.microformat ~= '-' then microformatClass = options.microformat or 'bday' end if ( options.nocat ) then return formatDateImpl( value, options, microformatClass, nil, options.leftBracket, options.rightBracket, options.nolinks, options.isGenitive ) else return formatDateImpl( value, options, microformatClass, 'Родившиеся', options.leftBracket, options.rightBracket, options.nolinks, options.isGenitive ) end end -- Reentry point for Wikidata Snak formatting function p.formatDeathDate( context, options, value ) if ( not context ) then error( 'context not specified'); end if ( not options ) then error( 'options not specified'); end if ( not value ) then error( 'value not specified'); end local microformatClass = nil if options.microformat ~= '-' then microformatClass = options.microformat or 'dday' end if ( options.nocat and options.nocat ~= '' ) then return formatDateImpl( value, options, microformatClass, nil, options.leftBracket, options.rightBracket, options.nolinks, options.isGenitive ) else return formatDateImpl( value, options, microformatClass, 'Умершие', options.leftBracket, options.rightBracket, options.nolinks, options.isGenitive ) end end -- Reentry point for Wikidata Snak formatting -- default one function p.formatDate( context, options, value ) if ( not context ) then error( 'context not specified'); end if ( not options ) then error( 'options not specified'); end if ( not value ) then error( 'value not specified'); end local microformatClass = options.microformat or nil if ( options.nocat and options.nocat ~= '' ) then return formatDateImpl( value, options, microformatClass, nil, options.leftBracket, options.rightBracket, options.nolinks, options.isGenitive ) else local categoryPrefix = options.categoryPrefix or nil return formatDateImpl( value, options, microformatClass, categoryPrefix, options.leftBracket, options.rightBracket, options.nolinks, options.isGenitive ) end end function p.formatDateIntervalProperty( context, options ) if ( not context ) then error( 'context not specified' ); end if ( not options ) then error( 'options not specified' ); end if ( not options.entity ) then error( 'options.entity missing' ); end -- Получение нужных утверждений local WDS = require( 'Module:WikidataSelectors' ) local fromProperty = options.property if options.from and options.from ~= '' then fromProperty = options.from end local fromClaims = WDS.load( options.entityId, fromProperty ) local toClaims = WDS.load( options.entityId, options.to ) if fromClaims == nil and toClaims == nil then return '' end local formattedFromClaims = {} if fromClaims then for i, claim in ipairs( fromClaims ) do local formattedStatement = context.formatStatement( options, claim ) if formattedStatement then formattedStatement = '<span class="wikidata-claim" data-wikidata-property-id="' .. string.upper( options.property ) .. '" data-wikidata-claim-id="' .. claim.id .. '">' .. formattedStatement .. '</span>' table.insert( formattedFromClaims, formattedStatement ) end end end local formattedToClaims = {} local toOptions = deepcopy( options ) toOptions.property = options.to toOptions.novalue = nowLabel if toClaims then for i, claim in ipairs( toClaims ) do local formattedStatement = context.formatStatement( toOptions, claim ) if formattedStatement then formattedStatement = '<span class="wikidata-claim" data-wikidata-property-id="' .. string.upper( toOptions.property ) .. '" data-wikidata-claim-id="' .. claim.id .. '">' .. formattedStatement .. '</span>' table.insert( formattedToClaims, formattedStatement ) end end end local out = '' local fromOut = mw.text.listToText( formattedFromClaims, options.separator, options.conjunction ) local toOut = mw.text.listToText( formattedToClaims, options.separator, options.conjunction ) if fromOut ~= '' or toOut ~= '' then if fromOut ~= '' then out = fromOut else out = '?' end if toOut ~= '' then out = out .. ' — ' .. toOut else local withinClaims = nil if options.within then WDS.load( options.entityId, options.within ) end if withinClaims == nil then out = 'с ' .. out else out = out .. ' — ' .. nowLabel end end end if out ~= '' then if options.before then out = options.before .. out end if options.after then out = out .. options.after end end return out end local lowestBoundary = '1582-10-05T00:00:00Z' local lastBoundary = '1918-01-31T00:00:00Z' local boundaries = { -- from (G) till next will be diff(G = J + diff), at current { lowestBoundary, 10 }, { '1700-02-29T00:00:00Z', 11 }, { '1800-02-29T00:00:00Z', 12 }, { '1900-02-29T00:00:00Z', 13 }, { lastBoundary, '' }, } -- Передаваемое время обязано быть по Юлианскому календарю (старому стилю) function p.formatAsJulian( julTimeISO8601, infocardClass, categoryNamePrefix, leftBracket, rightBracket, nolinks ) if 'table' == type( julTimeISO8601 ) then if julTimeISO8601.args and julTimeISO8601.args[1] then julTimeISO8601 = julTimeISO8601.args[1] else return 'unknown argument type: ' .. type( julTime ) .. ': ' .. table.tostring( julTime ) end end julTimeISO8601 = mw.text.trim( julTimeISO8601 ) julTimeISO8601 = string.gsub( julTimeISO8601, '^+', '' ) local julTime = parseISO8601( julTimeISO8601 ) local t = os.date( "*t", julTime ) if ( julTime < parseISO8601( lowestBoundary ) ) then -- only julian if string.find( julTimeISO8601, '-02-29T', 1, true ) then t = { year = t.year, month = 2, day = 29 } end return moduleDates.formatWikiImpl( t, t, infocardClass, categoryNamePrefix, leftBracket, rightBracket, nolinks ) end if ( julTimeISO8601 >= lastBoundary ) then return "''некорректная дата (юлианский календарь не используется после 1918-01-26)''" end -- julian and grigorian for i = 1, #boundaries, 1 do local b1 = boundaries[i][1] local b2 = boundaries[i + 1][1] if ( b1 <= julTimeISO8601 and julTimeISO8601 < b2 ) then local diff = boundaries[i][2] if string.sub( julTimeISO8601, 1, 10 ) == string.sub( boundaries[i][1], 1, 10 ) then t = { year = t.year, month = 2, day = 29 } diff = diff - 1 end local gregTime = os.date( "*t", julTime + diff * 24 * 60 * 60 ) return moduleDates.formatWikiImpl( t, gregTime, infocardClass, categoryNamePrefix, leftBracket, rightBracket, nolinks ) end end return "''ошибка в модуле Модуль:Wikidata/date''" end return p 12c2c34efd103d2938bd65421aa550e8c6f26da0 Модуль:Sources 828 32 61 2024-06-10T20:41:59Z wikipedia:ru>Stjn 0 возврат, сломало [[Википедия:Форум/Технический#Ошибка lua]] Scribunto text/plain ---@alias args table ---@alias frame { args: args, extensionTag: function, newChild: ( fun( args: args ): frame ) } ---@alias source { publication: source, [string]: any } ---@alias value: string | { id: string } ---@alias snak { datatype: string, snaktype: string, datavalue: { type: string, value: value } } ---@alias snaks table<string, table<number, snak>> ---@alias statement { mainsnak: snak, rank: string, qualifiers: snaks } ---@alias statements table<string, table<number, statement>> ---@alias map { name: string, ids: string[] }[]> ---@type table local p = {} ---@type table<string, string> local NORMATIVE_DOCUMENTS = { Q20754888 = 'Закон Российской Федерации', Q20754884 = 'Закон РСФСР', Q20873831 = 'Распоряжение Президента Российской Федерации', Q20873834 = 'Указ исполняющего обязанности Президента Российской Федерации', Q2061228 = 'Указ Президента Российской Федерации', } ---@type table<string, string> local LANG_CACHE = { Q150 = 'fr', Q188 = 'de', Q1321 = 'es', Q1860 = 'en', Q652 = 'it', Q7737 = 'ru', Q8798 = 'uk', } ---@type map local PROPERTY_MAP = { { name = 'sourceId', ids = { 'P248', 'P805' } }, { name = 'lang', ids = { 'P407', 'P364' } }, { name = 'author', ids = { 'P50', 'P2093' } }, { name = 'part', ids = { 'P958', 'P1810' } }, { name = 'title', ids = { 'P1476' } }, { name = 'subtitle', ids = { 'P1680' } }, { name = 'url', ids = { 'P953', 'P1065', 'P854', 'P973', 'P2699', 'P888' } }, { name = 'editor', ids = { 'P98' } }, { name = 'translator', ids = { 'P655' } }, { name = 'publication-id', ids = { 'P1433' } }, { name = 'edition', ids = { 'P393' } }, { name = 'publisher', ids = { 'P123' } }, { name = 'place', ids = { 'P291' } }, { name = 'volume', ids = { 'P478' } }, { name = 'issue', ids = { 'P433' } }, { name = 'dateOfCreation', ids = { 'P571' } }, { name = 'dateOfPublication', ids = { 'P577' } }, { name = 'pages', ids = { 'P304' } }, { name = 'numberOfPages', ids = { 'P1104' } }, { name = 'tirage', ids = { 'P1092' } }, { name = 'isbn', ids = { 'P212', 'P957' } }, { name = 'issn', ids = { 'P236' } }, -- { name = 'accessdate', ids = { 'P813' } }, -- disable, creates duplicate references { name = 'docNumber', ids = { 'P1545' } }, { name = 'type', ids = { 'P31' } }, { name = 'arxiv', ids = { 'P818' } }, { name = 'doi', ids = { 'P356' } }, { name = 'pmid', ids = { 'P698' } }, } -- table.insert( PROPERTY_MAP.url, 'P856' ) -- only as qualifier ---@type map local PUBLICATION_PROPERTY_MAP = mw.clone( PROPERTY_MAP ) ---@type string[] local monthGen = { 'января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря' } ---@type string local i18nDefaultLanguage = mw.language.getContentLanguage():getCode() p.i18nDefaultLanguage = i18nDefaultLanguage ---@type string local i18nEtAlDefault = ' et al.' ---@type table<string, string> local i18nEtAl = { ru = ' и др.', uk = ' та ін.', } ---@type table<string, string> local i18nEditors = { fr = '', de = 'Hrsg.: ', es = '', en = '', it = '', ru = 'под ред. ', uk = 'за ред. ', } ---@type table<string, string> local i18nTranslators = { fr = '', de = '', es = '', en = '', it = '', ru = 'пер. ', uk = 'пер. ', } ---@type table<string, string> local i18nVolume = { de = 'Vol.', fr = 'Vol.', es = 'Vol.', en = 'Vol.', it = 'Vol.', ru = 'Т.', uk = 'Т.', } ---@type table<string, string> local i18nIssue = { en = 'Iss.', ru = 'вып.', uk = 'вип.', } ---@type table<string, string> local i18nPages = { fr = 'P.', de = 'S.', es = 'P.', en = 'P.', it = 'P.', ru = 'С.', uk = 'С.', } ---@type table<string, string> local i18nNumberOfPages = { en = 'p.', ru = 'с.', } ---@type table<string, string> local i18nTirage = { en = 'ed. size: %d', ru = '%d экз.', } ---@param args args ---@return source local function getFilledArgs( args ) ---@type source local data = {} for key, value in pairs( args ) do if mw.text.trim( value ) ~= '' then if key == 1 then key = 'sourceId' end data[ key ] = mw.text.trim( value ) end end return data end ---Returns formatted pair {Family name(s), First name(s)} ---@param fullName string ---@return table<number, string> local function tokenizeName( fullName ) local space = '%s+' -- matches single or more spacing character local name = "(%a[%a%-']*)%.?" -- matches single name, have to start with letter, can contain apostrophe and hyphen, may end with dot local surname = "(%a[%a%-']*)" -- same as name, but can't end with dot local surnamePrefixes = { 'ван', 'van', 'де', 'de' } local nm, nm2, srn, srn2, pref fullName = ' ' .. fullName .. ' ' fullName = mw.ustring.gsub( fullName, ' оглы ', ' ' ) fullName = mw.text.trim( fullName ) -- Surname, Name local pattern = '^' .. surname .. ',' .. space .. name .. '$' srn, nm = mw.ustring.match( fullName, pattern ) if srn then return { srn, mw.ustring.sub( nm, 1, 1 ) .. '.' } end -- Surname, Name prefix for _, surnamePrefix in pairs( surnamePrefixes ) do pattern = '^' .. surname .. ',' .. space .. name .. space .. '(' .. surnamePrefix .. ')' .. '$' srn, nm, pref = mw.ustring.match( fullName, pattern ) if srn then return { mw.ustring.sub( pref ) .. ' ' .. srn, mw.ustring.sub( nm, 1, 1 ) .. '.' } end end -- Surname, Name Name pattern = '^' .. surname .. ',' .. space .. name .. space .. name .. '$' srn, nm, nm2 = mw.ustring.match( fullName, pattern ) if srn then return { srn, mw.ustring.sub( nm, 1, 1 ) .. '.&nbsp;' .. mw.ustring.sub( nm2, 1, 1 ) .. '.' } end -- Surname Surname, Name pattern = '^' .. surname .. space .. surname .. ',' .. space .. name .. '$' srn, srn2, nm = mw.ustring.match( fullName, pattern ) if srn then return { srn .. '&nbsp;' .. srn2, mw.ustring.sub( nm, 1, 1 ) .. '.' } end -- Name Name Surname pattern = '^' .. name .. space .. name .. space .. surname .. '$' nm, nm2, srn = mw.ustring.match( fullName, pattern ) if srn then return { srn, mw.ustring.sub( nm, 1, 1 ) .. '.&nbsp;' .. mw.ustring.sub( nm2, 1, 1 ) .. '.' } end -- Name Name prefix Surname for _, surnamePrefix in pairs( surnamePrefixes ) do pattern = '^' .. name .. space .. name .. space .. '(' .. surnamePrefix .. ')' .. space .. surname .. '$' nm, nm2, pref, srn = mw.ustring.match( fullName, pattern ) if srn then return { mw.ustring.sub( pref ) .. ' ' .. srn, mw.ustring.sub( nm, 1, 1 ) .. '.&nbsp;' .. mw.ustring.sub( nm2, 1, 1 ) .. '.' } end end -- Surname, Name Name prefix for _, surnamePrefix in pairs( surnamePrefixes ) do pattern = '^' .. surname .. ',' .. space .. name .. space .. name .. space .. '(' .. surnamePrefix .. ')' .. '$' srn, nm, nm2, pref = mw.ustring.match( fullName, pattern ) if srn then return { mw.ustring.sub( pref ) .. ' ' .. srn, mw.ustring.sub( nm, 1, 1 ) .. '.&nbsp;' .. mw.ustring.sub( nm2, 1, 1 ) .. '.' } end end -- Name{1,4} Surname for k = 1, 4 do pattern = '^' .. string.rep( name .. space, k ) .. surname .. '$' ---@type string[] local matched = { mw.ustring.match( fullName, pattern ) } if #matched ~= 0 then for j = 1, k do matched[ j ] = mw.ustring.sub( matched[ j ], 1, 1 ) end return { matched[ k + 1 ], table.concat( matched, '.&nbsp;', 1, k ) .. '.' } end end -- Surname Name{1,4} for k = 1, 4 do pattern = '^' .. surname .. string.rep( space .. name, k ) .. '$' ---@type string[] local matched = { mw.ustring.match( fullName, pattern ) } if #matched ~= 0 then for j = 2, k + 1 do matched[ j ] = mw.ustring.sub( matched[ j ], 1, 1 ) end return { matched[ 1 ], table.concat( matched, '.&nbsp;', 2, k + 1 ) .. '.' } end end return { fullName } end ---@param fullName string | nil ---@return string | nil local function personNameToAuthorName( fullName ) if not fullName then return nil end local tokenized = tokenizeName( fullName ) if #tokenized == 1 then return tokenized[ 1 ] end return tokenized[ 1 ] .. '&nbsp;' .. tokenized[ 2 ] end ---@param fullName string | nil ---@return string | nil local function personNameToResponsibleName( fullName ) if not fullName then return nil end local tokenized = tokenizeName( fullName ) if #tokenized == 1 then return tokenized[ 1 ] end return tokenized[ 2 ] .. '&nbsp;' .. tokenized[ 1 ] end ---@alias options { separator: string, conjunction: string, format: ( fun( data: string ): string ), nolinks: boolean, preferids: boolean, short: boolean } ---@type options local options_commas = { separator = ', ', conjunction = ', ', format = function( data ) return data end, nolinks = false, preferids = false, short = false, } ---@type options local options_commas_short = mw.clone( options_commas ) options_commas_short.short = true ---@type options local options_commas_it_short = mw.clone( options_commas_short ) options_commas_it_short.format = function( data ) return "''" .. data .. "''" end ---@type options local options_commas_nolinks = mw.clone( options_commas ) options_commas_nolinks.nolinks = true ---@type options local options_citetypes = { separator = ' ', conjunction = ' ', format = function( data ) return 'citetype_' .. data end, nolinks = true , preferids = true, short = false, } ---@type options local options_commas_authors = mw.clone( options_commas ) options_commas_authors.format = personNameToAuthorName ---@type options local options_commas_responsible = mw.clone( options_commas ) options_commas_responsible.format = personNameToResponsibleName ---@type options local options_ids = { separator = '; ', conjunction = '; ', format = function( id ) return id end, nolinks = true, preferids = false, short = false, } ---@type options local options_arxiv = mw.clone( options_ids ) options_arxiv.format = function( id ) return '[https://arxiv.org/abs/' .. id .. ' arXiv:' .. id .. ']' end ---@type options local options_doi = mw.clone( options_ids ) options_doi.format = function( doi ) return '[https://dx.doi.org/' .. doi .. ' doi:' .. doi .. ']' end ---@type options local options_issn = mw.clone( options_ids ) options_issn.format = function( issn ) return '[https://www.worldcat.org/issn/' .. issn .. ' ' .. issn .. ']' end ---@type options local options_pmid = mw.clone( options_ids ) options_pmid.format = function( pmid ) return '[https://www.ncbi.nlm.nih.gov/pubmed/?term=' .. pmid .. ' PMID:' .. pmid .. ']' end ---@param str string | nil ---@return boolean local function isEmpty( str ) return not str or #str == 0 end ---@param allQualifiers snaks ---@param qualifierPropertyId string ---@return string | nil local function getSingleStringQualifierValue( allQualifiers, qualifierPropertyId ) if not allQualifiers or not allQualifiers[ qualifierPropertyId ] then return nil end ---@type table<number, snak> local propertyQualifiers = allQualifiers[ qualifierPropertyId ] for _, qualifier in pairs( propertyQualifiers ) do if ( qualifier and qualifier.datatype == 'string' and qualifier.datavalue and qualifier.datavalue.type == 'string' and qualifier.datavalue.value ~= '' ) then return qualifier.datavalue.value end end return nil end ---@param data table ---@param resultProperty string ---@return void local function appendImpl_toTable( data, resultProperty ) if not data[ resultProperty ] then data[ resultProperty ] = {} elseif ( type( data[ resultProperty ] ) == 'string' or ( type( data[ resultProperty ] ) == 'table' and type( data[ resultProperty ].id ) == 'string' ) ) then data[ resultProperty ] = { data[ resultProperty ] } end end ---@param datavalue table ---@param qualifiers snaks ---@param data table ---@param propertyName string ---@param options table local function appendImpl( datavalue, qualifiers, data, propertyName, options ) data[ propertyName ] = data[ propertyName ] or {} if propertyName == 'issn' then table.insert( data[ propertyName ], datavalue.value ) elseif propertyName == 'url' or datavalue.type == 'url' then local value = datavalue.value if options.format then value = options.format( value ) end appendImpl_toTable( data, propertyName ) table.insert( data[ propertyName ], value ) elseif datavalue.type == 'string' then local value = getSingleStringQualifierValue( qualifiers, 'P1932' ) if not value then value = getSingleStringQualifierValue( qualifiers, 'P1810' ) end if not value then value = datavalue.value if options.format then value = options.format( value ) end end appendImpl_toTable(data, propertyName) local pos = getSingleStringQualifierValue( qualifiers, 'P1545' ) if pos then table.insert( data[ propertyName ], tonumber(pos), value ) else table.insert( data[ propertyName ], value ) end elseif datavalue.type == 'monolingualtext' then local value = datavalue.value.text if options.format then value = options.format( value ) end appendImpl_toTable( data, propertyName ) table.insert( data[ propertyName ], value ) elseif datavalue.type == 'quantity' then local value = datavalue.value.amount if ( mw.ustring.sub( value , 1, 1 ) == '+' ) then value = mw.ustring.sub( value , 2 ) end if options.format then value = options.format( value ) end appendImpl_toTable( data, propertyName ) table.insert( data[ propertyName ], value ) elseif datavalue.type == 'wikibase-entityid' then local pos = getSingleStringQualifierValue( qualifiers, 'P1545' ) local value = datavalue.value appendImpl_toTable(data, propertyName) local label = getSingleStringQualifierValue( qualifiers, 'P1932' ) if not label then label = getSingleStringQualifierValue( qualifiers, 'P1810' ) end local toInsert = { id = value.id, label = label } if pos and tonumber( pos ) then table.insert( data[ propertyName ], tonumber( pos ), toInsert ) else table.insert( data[ propertyName ], toInsert ) end elseif datavalue.type == 'time' then local value = datavalue.value if options.format then value = options.format( value ) end appendImpl_toTable( data, propertyName ) table.insert( data[ propertyName ], tostring( value.time ) ) end end ---@param entityId string ---@param propertyId string ---@return table<number, statement> local function getAllStatements( entityId, propertyId ) ---@type boolean, table<number, statement> local wdStatus, statements = pcall( mw.wikibase.getAllStatements, entityId, propertyId ) if wdStatus and statements then return statements end return {} end ---@param entityId string ---@param propertyId string ---@return table<number, statement> local function getBestStatements( entityId, propertyId ) ---@type boolean, table<number, statement> local wdStatus, statements = pcall( mw.wikibase.getBestStatements, entityId, propertyId ) if wdStatus and statements then return statements end return {} end ---@param entityId string ---@param projectToCheck string? ---@return string | nil local function getSitelink( entityId, projectToCheck ) ---@type boolean, string local wbStatus, sitelink if projectToCheck then wbStatus, sitelink = pcall( mw.wikibase.getSitelink, entityId, projectToCheck ) else wbStatus, sitelink = pcall( mw.wikibase.getSitelink, entityId ) end if not wbStatus then return nil end return sitelink end ---@param args any[] ---@return any | nil local function coalesce( args ) for _, arg in pairs( args ) do if not isEmpty( arg ) then return arg end end return nil end ---@param value any ---@return string | nil local function getSingle( value ) if type( value ) == 'string' then return tostring( value ) elseif type( value ) == 'table' then if value.id then return tostring( value.id ) end for _, tableValue in pairs( value ) do return getSingle( tableValue ) end end return nil end ---@param langEntityId string ---@return string | nil local function getLangCode( langEntityId ) if not langEntityId then return nil end langEntityId = getSingle( langEntityId ) if not string.match( langEntityId, '^Q%d+$' ) then return langEntityId end local cached = LANG_CACHE[ langEntityId ] if cached then if cached == '' then return nil end return cached end local claims = getBestStatements( langEntityId, 'P424' ) for _, claim in pairs( claims ) do if claim and claim.mainsnak and claim.mainsnak.datavalue and claim.mainsnak.datavalue.value then LANG_CACHE[ langEntityId ] = claim.mainsnak.datavalue.value return claim.mainsnak.datavalue.value end end LANG_CACHE[ langEntityId ] = '' return nil end ---@param entityId string ---@param propertyId string ---@param data source ---@param propertyName string ---@param options table? ---@return void local function appendEntitySnaks( entityId, propertyId, data, propertyName, options ) options = options or {} -- do not populate twice if data[ propertyName ] and ( propertyName ~= 'author' or data[ propertyId ] ) then return end local statements = getBestStatements( entityId, propertyId ) if propertyName == 'author' then data[ propertyId ] = true end local lang = getLangCode( data.lang ) or i18nDefaultLanguage if propertyId == 'P1680' then -- if there is a default language for _, statement in pairs( statements ) do if statement and statement.mainsnak and statement.mainsnak.datavalue and statement.mainsnak.datavalue.value and statement.mainsnak.datavalue.value.language == lang then --found default language string appendImpl( statement.mainsnak.datavalue, statement.qualifiers, data, propertyName, options ) return end end end for _, statement in pairs( statements ) do if statement and statement.mainsnak and statement.mainsnak.datavalue then appendImpl( statement.mainsnak.datavalue, statement.qualifiers or {}, data, propertyName, options ) if propertyName == 'publication-id' and statement.qualifiers then data[ 'publication-qualifiers' ] = statement.qualifiers end end end end ---@param claims table<number, statement> ---@param qualifierPropertyId string ---@param result table ---@param resultPropertyId string ---@param options table ---@return void local function appendQualifiers( claims, qualifierPropertyId, result, resultPropertyId, options ) -- do not populate twice if not claims or result[ resultPropertyId ] then return end for _, claim in pairs( claims ) do if claim.qualifiers and claim.qualifiers[ qualifierPropertyId ] then ---@type table<number, snak> local propertyQualifiers = claim.qualifiers[ qualifierPropertyId ] for _, qualifier in pairs( propertyQualifiers ) do if qualifier and qualifier.datavalue then appendImpl( qualifier.datavalue, nil, result, resultPropertyId, options ) end end end end end ---@param entityId string ---@param propertyId string ---@param value any ---@return table<number, statement> local function findClaimsByValue( entityId, propertyId, value ) local result = {} local claims = getAllStatements( entityId, propertyId ) for _, claim in pairs( claims ) do if ( claim.mainsnak and claim.mainsnak.datavalue ) then local datavalue = claim.mainsnak.datavalue if ( datavalue.type == "string" and datavalue.value == value ) or ( datavalue.type == "wikibase-entityid" and datavalue.value[ "entity-type" ] == "item" and tostring( datavalue.value.id ) == value ) then table.insert( result, claim ) end end end return result end ---@param entityId string ---@param typeEntityId string ---@return boolean local function isInstanceOf( entityId, typeEntityId ) return findClaimsByValue( entityId, 'P31', typeEntityId )[ 1 ] ~= nil end ---@param entityId string ---@param typeEntityIds string[] ---@return string ---@todo Rewrite local function getFirstType( entityId, typeEntityIds ) for _, typeEntityId in pairs( typeEntityIds ) do if isInstanceOf( entityId, typeEntityId ) then return typeEntityId end end return nil end ---@param snaks snaks ---@param data source ---@param map map ---@return void local function populateDataFromSnaks( snaks, data, map ) for _, row in ipairs( map ) do local parameterName, propertyIds = row.name, row.ids for _, propertyId in pairs( propertyIds ) do if not data[ parameterName ] and snaks[ propertyId ] then local options = {} if propertyId == 'P888' then options = { format = function( id ) return 'http://www.jstor.org/stable/' .. id end } end for _, snak in pairs( snaks[ propertyId ] ) do if snak and snak.datavalue then appendImpl( snak.datavalue, {}, data, parameterName, options ) end end end end end end ---@param entityId string | nil ---@param data source ---@param map map ---@return void local function populateDataFromEntity( entityId, data, map ) if not data.title then if not isEmpty( entityId ) then local optionsAsLinks = { format = function( text ) return { id = entityId, label = text } end } appendEntitySnaks( entityId, 'P1476', data, 'title', optionsAsLinks ) else appendEntitySnaks( entityId, 'P1476', data, 'title', {} ) end appendEntitySnaks( entityId, 'P1680', data, 'subtitle', {} ) end local bookSeriesStatements = getBestStatements( entityId, 'P361' ) for _, statement in pairs( bookSeriesStatements ) do if statement and statement.mainsnak and statement.mainsnak.datavalue and statement.mainsnak.datavalue.value and statement.mainsnak.datavalue.value.id then local possibleBookSeriesEntityId = statement.mainsnak.datavalue.value.id if isInstanceOf( possibleBookSeriesEntityId, 'Q277759' ) then appendImpl_toTable( data, 'bookSeries' ) table.insert( data.bookSeries, { id = possibleBookSeriesEntityId } ) appendQualifiers( { statement }, 'P478', data, 'bookSeriesVolume', {} ) appendQualifiers( { statement }, 'P433', data, 'bookSeriesIssue', {} ) end end end for _, row in ipairs( map ) do local parameterName, propertyIds = row.name, row.ids for _, propertyId in pairs( propertyIds ) do local options = {} if propertyId == 'P888' then options = { format = function( id ) return 'http://www.jstor.org/stable/' .. id end } end appendEntitySnaks( entityId, propertyId, data, parameterName, options ) end end end ---@param data source ---@return void local function expandPublication( data ) if not data[ 'publication-id' ] then return end local publicationId = getSingle( data[ 'publication-id' ] ) data.publication = {} for key, value in pairs( data ) do if not string.match( key, '^publication-' ) then data.publication[ key ] = value end end data.publication.sourceId = publicationId data.publication.title = data[ 'publication-title' ] data.publication.subtitle = data[ 'publication-subtitle' ] if data[ 'publication-qualifiers' ] then populateDataFromSnaks( data[ 'publication-qualifiers' ], data.publication, PUBLICATION_PROPERTY_MAP ) end populateDataFromEntity( publicationId, data.publication, PUBLICATION_PROPERTY_MAP ) if type( data.publication.title ) == 'table' and data.publication.title[ 1 ] then data.publication.title = data.publication.title[ 1 ] end if type( data.publication.subtitle ) == 'table' and data.publication.subtitle[ 1 ] then data.publication.subtitle = data.publication.subtitle[ 1 ] end for key, value in pairs( data.publication ) do if key ~= 'sourceId' and key ~= 'title' and key ~= 'subtitle' and key ~= 'url' and not data[ key ] then data[ key ] = value end end end ---@param data source ---@return void local function expandBookSeries( data ) local bookSeries = data.bookSeries if not bookSeries then return end -- use only first one if type( bookSeries ) == 'table' and bookSeries[ 1 ] and bookSeries[ 1 ].id then data.bookSeries = bookSeries[ 1 ] bookSeries = data.bookSeries end if not bookSeries or not bookSeries.id then return end appendEntitySnaks( bookSeries.id, 'P123', data, 'publisher', {} ) appendEntitySnaks( bookSeries.id, 'P291', data, 'place', {} ) appendEntitySnaks( bookSeries.id, 'P236', data, 'issn', {} ) end ---@param entityId string ---@return string | nil local function getNormativeTitle( entityId ) local possibleTypeIds = {} for typeId, _ in pairs( NORMATIVE_DOCUMENTS ) do table.insert( possibleTypeIds, typeId ) end local foundTypeId = getFirstType( entityId, possibleTypeIds ) if foundTypeId then return NORMATIVE_DOCUMENTS[ foundTypeId ] end return nil end ---@param urls table<number, string> | string ---@param text string ---@return string local function wrapInUrl( urls, text ) local url = getSingle( urls ) if string.sub( url, 1, 1 ) == ':' then return '[[' .. url .. '|' .. text .. ']]' else return '[' .. url .. ' ' .. text .. ']' end end ---@param entityId string ---@param lang string ---@return string local function getElementLink( entityId, lang ) local sitelink = getSitelink( entityId, nil ) if sitelink then return ':' .. sitelink end if lang ~= 'mul' then -- link to entity in source language sitelink = getSitelink( entityId, lang .. 'wiki' ) if sitelink then return ':' .. lang .. ':' .. sitelink end end return ':d:' .. entityId end ---@param entityId string ---@param lang string ---@return string local function getLabel( entityId, lang ) local wbStatus, label = pcall( mw.wikibase.getLabelByLang, entityId, lang ) if not wbStatus then return '' end if label and label ~= '' then return label end wbStatus, label = pcall( mw.wikibase.getLabel, entityId ) if not wbStatus then return '' end return label or '' end ---@param lang string ---@param entityId string ---@param customTitle string ---@param options table local function renderLink( lang, entityId, customTitle, options ) if not entityId then error( 'entityId is not specified' ) end if type( entityId ) ~= 'string' then error( 'entityId is not string, but ' .. type( entityId ) ) end if type( customTitle or '' ) ~= 'string' then error( 'customTitle is not string, but ' .. type( customTitle ) ) end local title = customTitle -- ISO 4 if isEmpty( title ) then local propertyStatements = getBestStatements( entityId, 'P1160' ) for _, claim in pairs( propertyStatements ) do if ( claim and claim.mainsnak and claim.mainsnak.datavalue and claim.mainsnak.datavalue.value and claim.mainsnak.datavalue.value.language == lang ) then title = claim.mainsnak.datavalue.value.text -- mw.log( 'Got title of ' .. entityId .. ' from ISO 4 claim: «' .. title .. '»' ) break end end end -- official name P1448 -- short name P1813 if isEmpty( title ) and options.short then local propertyStatements = getBestStatements( entityId, 'P1813' ) for _, claim in pairs( propertyStatements ) do if ( claim and claim.mainsnak and claim.mainsnak.datavalue and claim.mainsnak.datavalue.value and claim.mainsnak.datavalue.value.language == lang ) then title = claim.mainsnak.datavalue.value.text -- mw.log( 'Got title of ' .. entityId .. ' from short name claim: «' .. title .. '» (' .. lang .. ')' ) break end end end -- person name P1559 -- labels if isEmpty( title ) then title = getLabel( entityId, lang ) -- mw.log( 'Got title of ' .. entityId .. ' from label: «' .. title .. '» (' .. lang .. ')' ) end local actualText = title or '\'\'(untranslated)\'\'' local link = getElementLink( entityId, lang ) return wrapInUrl( link, actualText ) end ---@param lang string ---@param value value ---@param options options ---@return string local function asString( lang, value, options ) if type( value ) == 'string' then return options.format( value ) end if type( value ) ~= 'table' then return options.format( '(unknown type)' ) end if value.id then -- this is link if type( value.label or '' ) ~= 'string' then mw.logObject( value, 'error value' ) error( 'label of table value is not string but ' .. type( value.label ) ) end local title if options.preferids then title = value.id elseif options.nolinks then title = value.label or getLabel( value.id, lang ) else title = renderLink( lang, value.id, value.label, options ) end if title == '' then title = "''(untranslated title)''" end return options.format( title ) end local resultList = {} for _, tableValue in pairs( value ) do table.insert( resultList, asString( lang, tableValue, options ) ) end return mw.text.listToText( resultList, options.separator, options.conjunction ) end ---@param entityId string ---@param data source ---@return source local function populateSourceDataImpl( entityId, data, map ) local wsLink = getSitelink( entityId, 'ruwikisource' ) if wsLink and not mw.ustring.gmatch( wsLink, 'Категория:' ) then data.url = ":ru:s:" .. wsLink end populateDataFromEntity( entityId, data, map ) local normativeTitle = getNormativeTitle( entityId ) if normativeTitle then local y, m, d = mw.ustring.match( getSingle( data.dateOfCreation ) , "(%-?%d+)%-(%d+)%-(%d+)T" ) y, m, d = tonumber( y ),tonumber( m ), tonumber( d ) local title = asString( 'ru', data.title, options_commas_nolinks ) local docNumber = getSingle( data.docNumber ) data.title = { normativeTitle .. " от&nbsp;" .. tostring( d ) .. "&nbsp;" .. monthGen[ m ] .. " " .. tostring( y ) .. "&nbsp;г." .. ( docNumber and ( " №&nbsp;" .. docNumber ) or '' ) .. ' «' .. title.. '»' } end if not data.title then local lang = getLangCode( data.lang ) or i18nDefaultLanguage local label = getLabel( entityId, lang ) if label ~= '' then data.title = { label } end end return data end ---@param entityId string ---@param propertyId string ---@param data source ---@return void local function expandSpecialsQualifiers( entityId, propertyId, data ) local statements = getBestStatements( entityId, propertyId ) for _, statement in pairs( statements ) do populateDataFromSnaks( statement.qualifiers or {}, data, PROPERTY_MAP ) end end ---Expand special types of references when additional data could be found in OTHER entity properties ---@param data source ---@return void local function expandSpecials( data ) if not data.entityId then return end if data.sourceId == 'Q36578' then -- Gemeinsame Normdatei -- specified by P227 appendEntitySnaks( data.entityId, 'P227', data, 'part', { format = function(gnd ) return 'Record #' .. gnd; end } ) appendEntitySnaks( data.entityId, 'P227', data, 'url', { format = function(gnd ) return 'http://d-nb.info/gnd/' .. gnd .. '/'; end } ) data.year = '2012—2016' expandSpecialsQualifiers( data.entityId, 'P227', data ) elseif data.sourceId == 'Q15222191' then -- BNF -- specified by P268 appendEntitySnaks( data.entityId, 'P268', data, 'part', { format = function(id ) return 'Record #' .. id; end } ) appendEntitySnaks( data.entityId, 'P268', data, 'url', { format = function(id ) return 'http://catalogue.bnf.fr/ark:/12148/cb' .. id; end } ) expandSpecialsQualifiers( data.entityId, 'P268', data ) elseif data.sourceId == 'Q54919' then -- VIAF -- specified by P214 appendEntitySnaks( data.entityId, 'P214', data, 'part', { format = function(id ) return 'Record #' .. id; end } ) appendEntitySnaks( data.entityId, 'P214', data, 'url', { format = function(id ) return 'https://viaf.org/viaf/' .. id; end } ) expandSpecialsQualifiers( data.entityId, 'P214', data ) else -- generic property search for _, sourceClaim in pairs( getBestStatements( data.sourceId, 'P1687' ) ) do if sourceClaim.mainsnak.snaktype == 'value' then local sourcePropertyId = sourceClaim.mainsnak.datavalue.value.id for _, sourcePropertyClaim in pairs( getBestStatements( sourcePropertyId, 'P1630' ) ) do if sourcePropertyClaim.mainsnak.snaktype == 'value' then appendEntitySnaks( data.entityId, sourcePropertyId, data, 'url', { format = function( id ) return mw.ustring.gsub( mw.ustring.gsub( sourcePropertyClaim.mainsnak.datavalue.value, '$1', id ), ' ', '%%20' ) end } ) expandSpecialsQualifiers( data.entityId, sourcePropertyId, data ) break end end end end end -- do we have appropriate record in P1433 ? local claims = findClaimsByValue( currentEntityId, 'P1343', data.sourceId ) if claims and #claims ~= 0 then for _, claim in pairs( claims ) do populateDataFromSnaks( claim.qualifiers, data, PROPERTY_MAP ) populateDataFromEntity( data.sourceId, data, PROPERTY_MAP ) end end end ---@param text string ---@param tip string ---@return string local function toTextWithTip( text, tip ) return '<span title="' .. tip .. '" style="border-bottom: 1px dotted; cursor: help; white-space: nowrap">' .. text .. '</span>' end ---@param lang string ---@param placeId string ---@return string local function getPlaceName( placeId, lang ) -- ГОСТ Р 7.0.12—2011 if lang == 'ru' then if placeId == 'Q649' then return toTextWithTip( 'М.', 'Москва' ); end if placeId == 'Q656' then return toTextWithTip( 'СПб.', 'Санкт-Петербург' ); end if placeId == 'Q891' then return toTextWithTip( 'Н. Новгород', 'Нижний Новгород' ); end if placeId == 'Q908' then return toTextWithTip( 'Ростов н/Д.', 'Ростов-на-Дону' ); end end return nil end ---@param data source ---@param lang string ---@return void local function preprocessPlace( data, lang ) if not data.place then return end ---@type table<number, string> local newPlace = {} for index, place in pairs( data.place ) do if place.id then local newPlaceStr = getPlaceName( place.id, lang ) if newPlaceStr then newPlace[ index ] = newPlaceStr else newPlace[ index ] = getLabel( place.id, lang ) end else newPlace[ index ] = place end end data.place = newPlace end ---@param entityId string ---@param lang string ---@param providedLabel string | nil ---@param options options ---@return string local function getPersonNameAsLabel( entityId, lang, providedLabel, options ) -- would custom label provided we don't need to check entity at all if not isEmpty( providedLabel ) then return options.format( providedLabel ) end if lang == 'mul' then lang = i18nDefaultLanguage end ---@type string | nil local personName = getLabel( entityId, lang ) if isEmpty( personName ) then return '\'\'(not translated to ' .. lang .. ')\'\'' end if not isInstanceOf( entityId, 'Q5' ) then return personName end return options.format( personName ) end ---@param entityId string ---@param lang string ---@param customLabel string | nil ---@param options options ---@return string local function getPersonNameAsWikitext( entityId, lang, customLabel, options ) local personName = getPersonNameAsLabel( entityId, lang, customLabel, options ) local link = getElementLink( entityId, lang ) return wrapInUrl( link, personName ) end ---@param value value ---@param lang string ---@param options options ---@return string local function getPeopleAsWikitext( value, lang, options ) if type( value ) == 'string' then return options.format( value ) elseif type( value ) == 'table' then if value.id then -- this is link if options.preferids then return tostring( value.id ) else if options.nolinks then return getPersonNameAsLabel( value.id, lang, value.label, options ) else return getPersonNameAsWikitext( value.id, lang, value.label, options ) end end end local maxAuthors = 10 -- need some restrictions, as some publications have enormous amount of authors (e.g. 115 authors of Q68951544) local resultList = {} for _, tableValue in pairs( value ) do local nextWikitext = getPeopleAsWikitext( tableValue, lang, options ) if not isEmpty( nextWikitext ) then table.insert( resultList, nextWikitext ) if #resultList == maxAuthors + 1 then -- keep one more to indicate that there are too many break end end end local resultWikitext = '' for i, wikitext in pairs( resultList ) do if i == maxAuthors + 1 then resultWikitext = resultWikitext .. ( i18nEtAl[ lang ] or i18nEtAlDefault ) break end if i ~= 1 then resultWikitext = resultWikitext .. ', ' end resultWikitext = resultWikitext .. wikitext end return resultWikitext end return '' -- options.format( '(unknown type)' ) end ---@param lang string ---@param data source ---@return string local function generateAuthorLinks( lang, data ) local result = '' if data.author then result = getPeopleAsWikitext( data.author, lang, options_commas_authors ) result = '<i class="wef_low_priority_links">' .. result .. '</i> ' end return result end ---@param lang string ---@param data source ---@param conjunction string ---@param propertyName string ---@param urlPropertyName string? ---@return string local function appendProperty( lang, data, conjunction, propertyName, urlPropertyName ) if not data[ propertyName ] then return '' end local out if urlPropertyName and data[ urlPropertyName ] then out = wrapInUrl( data[ urlPropertyName ], asString( lang, data[ propertyName ], options_commas_nolinks ) ) else out = asString( lang, data[ propertyName ], options_commas ) end if not out or out == '' then return '' end return conjunction .. out end ---@param lang string ---@param data source ---@return string local function appendTitle( lang, data ) local conjunction = '' local result = '' if data.part then result = result .. appendProperty( lang, data, '', 'part', 'parturl' ) conjunction = ' // ' end return result .. appendProperty( lang, data, conjunction, 'title', 'url' ) end ---@param lang string ---@return string local function appendLanguage( lang ) if lang == i18nDefaultLanguage then return '' end ---@type { getRefHtml: ( fun( lang: string ): string ), list_ref: ( fun( frame: frame ): string ) } local langs = require( 'Module:Languages' ) return langs.list_ref( p.currentFrame:newChild{ args = { lang } } ) end ---@param lang string ---@param data source ---@return string local function appendSubtitle( lang, data ) return appendProperty( lang, data, ': ', 'subtitle', nil ) end ---@param lang string ---@param data source ---@return string local function appendOriginalTitle( lang, data ) return appendProperty( lang, data, ' = ', 'originaltitle', nil ) end ---@param lang string ---@param data source ---@return string local function appendPublication( lang, data ) if not data.publication then return '' end local result = ' // ' .. asString( lang, data.publication.title, options_commas_it_short ) if data.publication.subtitle and data.publication.subtitle ~= '' then result = result .. ': ' .. asString( lang, data.publication.subtitle, options_commas_it_short ) end return result end ---@param lang string ---@param data source ---@return string local function appendEditor( lang, data ) if not data.editor and not data.translator then return '' end local result = ' / ' if data.editor then local prefix = i18nEditors[ lang ] or i18nEditors[ i18nDefaultLanguage ] result = result .. prefix .. getPeopleAsWikitext( data.editor, lang, options_commas_responsible ) if data.translator then result = result .. ', ' end end if data.translator then local prefix = i18nTranslators[ lang ] or i18nTranslators[ i18nDefaultLanguage ] result = result .. prefix .. getPeopleAsWikitext( data.translator, lang, options_commas_responsible ) end return result end ---@param lang string ---@param data source local function appendEdition( lang, data ) return appendProperty( lang, data, ' — ', 'edition', nil ) end ---@param lang string ---@param data source ---@return string local function appendPublicationData( lang, data ) if not data.place and not data.publisher and not data.year then return '' end local result = ' — ' if data.place then result = result .. asString( lang, data.place, options_commas_short ) if data.publisher or data.year then result = result .. ': ' end end if data.publisher then result = result .. asString( lang, data.publisher, options_commas_short ) if data.year then result = result .. ', ' end end if data.year then result = result .. asString( lang, data.year, options_commas ) end result = result .. '.' return result end ---@param lang string ---@param data source ---@return string local function appendVolumeAndIssue( lang, data ) if not data.volume and not data.issue then return '' end local result = ' — ' local letter_vol = i18nVolume[ lang ] or i18nVolume[ i18nDefaultLanguage ] local letter_iss = i18nIssue[ lang ] or i18nIssue[ i18nDefaultLanguage ] if data.volume then result = result .. appendProperty( lang, data, letter_vol .. '&nbsp;', 'volume', nil ) result = result ..appendProperty( lang, data, ', ' .. letter_iss .. '&nbsp;', 'issue', nil ) else result = result .. appendProperty( lang, data, letter_iss .. '&nbsp;', 'issue', nil ) end result = result .. '.' return result end ---@param lang string ---@param data source ---@return string local function appendPages( lang, data ) if not data.pages then return '' end local letter = i18nPages[ lang ] or i18nPages[ i18nDefaultLanguage ] local strPages = asString( lang, data.pages, options_commas ) strPages = mw.ustring.gsub( strPages, '[-—]', '—' ) return ' — ' .. letter .. '&nbsp;' .. strPages .. '.' end ---@param lang string ---@param data source ---@return string local function appendNumberOfPages( lang, data ) if not data.numberOfPages then return '' end local letter = i18nNumberOfPages[ lang ] or i18nNumberOfPages[ i18nDefaultLanguage ] return appendProperty( lang, data, ' — ', 'numberOfPages', nil ) .. '&nbsp;' .. letter end ---@param lang string ---@param data source ---@return string local function appendBookSeries( lang, data ) if not data.bookSeries then return '' end local result = appendProperty( lang, data, ' — (', 'bookSeries', nil ) if data.bookSeriesVolume or data.bookSeriesIssue then result = result .. '; ' local letter_vol = i18nVolume[ lang ] or i18nVolume[ i18nDefaultLanguage ] local letter_iss = i18nIssue[ lang ] or i18nIssue[ i18nDefaultLanguage ] if data.bookSeriesVolume then result = result .. appendProperty( lang, data, letter_vol .. '&nbsp;', 'bookSeriesVolume', nil ) result = result .. appendProperty( lang, data, ', ' .. letter_iss .. '&nbsp;', 'bookSeriesIssue', nil ) else result = result .. appendProperty( lang, data, letter_iss .. '&nbsp;', 'bookSeriesIssue', nil ) end end result = result .. ')' return result end ---@param lang string ---@param data source ---@return string local function appendTirage( lang, data ) if not data.tirage then return '' end local tirageTemplate = i18nTirage[ lang ] or i18nTirage[ i18nDefaultLanguage ] ---@type options local optionsTirage = { separator = '; ', conjunction = '; ', format = function( _data ) return tostring( mw.ustring.format( tirageTemplate, _data ) ) end, short = false, nolinks = false, preferids = false, } return ' — ' .. asString( lang, data.tirage, optionsTirage ) end ---@param lang string ---@param value string | nil ---@param options options ---@param prefix string? ---@return string local function appendIdentifier( lang, value, options, prefix ) if not value then return '' end return ' — ' .. ( prefix or '' ) .. asString( lang, value, options ) end ---@param result string ---@param lang string ---@param data source ---@return string local function wrapSourceId( result, lang, data ) if not data.sourceId then return result end local citeType = data.type and asString( lang, data.type, options_citetypes ) or 'citetype_unknown' return '<span class="wikidata_cite ' .. citeType .. '" data-entity-id="' .. data.sourceId .. '">' .. result .. '</span>' end ---@param data source ---@return string local function appendAccessDate( data ) if not data.accessdate then return '' end local date = getSingle( data.accessdate ) local pattern = "(%-?%d+)%-(%d+)%-(%d+)T" local y, m, d = mw.ustring.match( date, pattern ) y, m, d = tonumber( y ), tonumber( m ), tonumber( d ) local date_str = ( d > 0 and ' ' .. tostring( d ) or '' ) .. ( m > 0 and ' ' .. monthGen[ m ] or '' ) .. ( y > 0 and ' ' .. tostring( y ) or '' ) return " <small>Проверено" .. date_str .. ".</small>" end ---@param data source ---@param lang string ---@return void local function populateUrl( data, lang ) if data.sourceId and not data.url then local sitelink = getSitelink( data.sourceId, lang .. 'wikisource' ) if sitelink then data.url = ':' .. lang .. ':s:' .. sitelink end end end ---@param data source ---@return void local function populateYear( data ) if not data.year and data.dateOfPublication then local date = getSingle( data.dateOfPublication ) data.year = mw.ustring.sub( date, 2, 5 ) end if not data.year and data.dateOfCreation then local date = getSingle( data.dateOfCreation ) data.year = mw.ustring.sub( date, 2, 5 ) end end ---@param data source ---@return void local function populateTitle( data ) data.title = data.title or getSingle( data.url ) end ---@param data source ---@return string local function renderSource( data ) local lang = getLangCode( data.lang ) or i18nDefaultLanguage preprocessPlace( data, lang ) populateUrl( data, lang ) populateTitle( data ) if not data.title then return '' end populateYear( data ) local result = generateAuthorLinks( lang, data ) result = result .. appendTitle( lang, data ) result = result .. appendLanguage( lang ) result = result .. appendSubtitle( lang, data ) result = result .. appendOriginalTitle( lang, data ) result = result .. appendPublication( lang, data ) result = result .. '<span class="wef_low_priority_links">' result = result .. appendEditor( lang, data ) -- Might take current editor instead of actual. Use with caution result = result .. appendEdition( lang, data ) result = result .. appendPublicationData( lang, data ) result = result .. appendVolumeAndIssue( lang, data ) result = result .. appendPages( lang, data ) result = result .. appendNumberOfPages( lang, data ) result = result .. appendBookSeries( lang, data ) result = result .. appendTirage( lang, data ) result = result .. appendIdentifier( lang, data.isbn, options_commas, 'ISBN ' ) result = result .. appendIdentifier( lang, data.issn, options_issn, 'ISSN ' ) result = result .. appendIdentifier( lang, data.doi, options_doi, nil ) result = result .. appendIdentifier( lang, data.pmid, options_pmid, nil ) result = result .. appendIdentifier( lang, data.arxiv, options_arxiv, nil ) result = result .. appendAccessDate( data ) result = result .. '</span>' return wrapSourceId( result, lang, data ) end ---@param data source Данные в простом формате, согласованном с модулями формирования библиографического описания ---@param snaks snaks ---@return string | nil local function renderReferenceImpl( data, snaks ) -- не показывать источники с "импортировано из" if snaks.P143 then return nil end -- забрать данные из reference populateDataFromSnaks( snaks or {}, data, PROPERTY_MAP ) data.sourceId = getSingle( data.sourceId ) populateDataFromEntity( data.sourceId, data, PROPERTY_MAP ) expandSpecials( data ) populateSourceDataImpl( data.sourceId, data, PROPERTY_MAP ) expandPublication( data ) expandBookSeries( data ) if next( data ) == nil then return nil end local rendered = renderSource( data ) if mw.ustring.len( rendered ) == 0 then return nil end if data.ref then local anchorValue = 'CITEREF' .. data.ref .. ( coalesce( { data[ 'ref-year' ], data.year } ) or '' ) rendered = '<span class="citation" id="' .. mw.uri.anchorEncode( anchorValue ) .. '">' .. rendered .. '</span>' end return rendered end ---@param frame frame ---@param currentEntityId string | { id: string } ---@param reference table{ snaks: snaks } ---@return string | nil function p.renderSource( frame, currentEntityId, reference ) reference = reference or { snaks = {} } p.currentFrame = frame local data = getFilledArgs( frame.args or {} ) populateDataFromSnaks( reference.snaks, data, PROPERTY_MAP ) data.sourceId = getSingle( data.sourceId ) if not currentEntityId then data.entityId = mw.wikibase.getEntityIdForCurrentPage() elseif type( currentEntityId ) == 'string' then data.entityId = currentEntityId elseif type( currentEntityId ) == 'table' and currentEntityId.id then data.entityId = currentEntityId.id end ---@type string local rendered = renderReferenceImpl( data, reference.snaks or {} ) if not rendered then return '' end return rendered end ---@param frame frame ---@param currentEntityId string ---@param reference table ---@return string function p.renderReference( frame, currentEntityId, reference ) local rendered = p.renderSource( frame, currentEntityId, reference ) if not rendered or rendered == '' then return '' end -- Про выбор алгоритма хеширования см. [[Модуль:Hash]]. Знак подчёркивания в начале позволяет -- исключить ошибку, когда имя сноски — чисто числовое значение, каковыми иногда бывают хеши. return frame:extensionTag( 'ref', rendered, { name = '_' .. mw.hash.hashValue( 'fnv164', rendered ) } ) .. '[[Category:Википедия:Статьи с источниками из Викиданных]]' end ---@param frame frame ---@return string | nil function p.testPersonNameToAuthorName( frame ) return personNameToAuthorName( frame.args[ 1 ] ) end ---@param frame frame ---@return string | nil function p.testPersonNameToResponsibleName( frame ) return personNameToResponsibleName( frame.args[ 1 ] ) end return p 752a204827a41ecd6cf518bdb22da12718bca2ec Модуль:Message box/ombox.css 828 111 219 2024-06-21T16:47:35Z wikipedia:ru>Putnik 0 исправление цвета рамки text text/plain /* Скопировано из [[:en:Module:Message box/ombox.css]] */ .ombox { margin: 4px 0; border-collapse: collapse; border: 1px solid var(--border-color-base, #a2a9b1); /* Default "notice" gray */ background-color: var(--background-color-neutral-subtle, #f8f9fa); box-sizing: border-box; } /* For the "small=yes" option. */ .ombox.mbox-small { font-size: 88%; line-height: 1.25em; } .ombox-speedy { border: 2px solid var(--border-color-error, #b32424); /* Red */ background-color: var(--background-color-error-subtle, #fee7e6); /* Pink */ } .ombox-delete { border: 2px solid var(--background-color-error--active, #b32424); /* Red */ } .ombox-content { border: 1px solid #f28500; /* Orange */ } .ombox-style { border: 1px solid #fc3; /* Yellow */ } .ombox-move { border: 1px solid #9932cc; /* Purple */ } .ombox-protection { border: 2px solid var(--border-color-base, #a2a9b1); /* Gray-gold */ } .ombox .mbox-text { border: none; /* @noflip */ padding: 0.25em 0.9em; width: 100%; } .ombox .mbox-image { border: none; /* @noflip */ padding: 2px 0 2px 0.9em; text-align: center; } .ombox .mbox-imageright { border: none; /* @noflip */ padding: 2px 0.9em 2px 0; text-align: center; } /* An empty narrow cell */ .ombox .mbox-empty-cell { border: none; padding: 0; width: 1px; } .ombox .mbox-invalid-type { text-align: center; } /* Хак, TODO: посмотреть, как оно на самом деле работает */ .ombox .mbox-textsmall-div { font-size: 90%; } @media (min-width: 720px) { .ombox { margin: 4px 10%; } .ombox.mbox-small { /* @noflip */ clear: right; /* @noflip */ float: right; /* @noflip */ margin: 4px 0 4px 1em; width: 238px; } /* Стили нотификаций для ноутбуков */ @media (max-width: 1366px) { .ombox { margin-left: 6%; margin-right: 6%; } } } /* [[Категория:Модули:Подстраницы CSS]] */ 6627874170f6674674bfa5796b2f7dfb6698cd81 Шаблон:Doc/begin 10 83 163 2024-06-30T22:14:58Z wikipedia:ru>Putnik 0 [[ВП:×|отмена]] правки 138443392 участника [[Special:Contribs/Putnik|Putnik]] ([[UT:Putnik|обс.]]) wikitext text/x-wiki <includeonly><templatestyles src="Шаблон:Doc/styles.css" /> <div class="ts-doc-doc" id="doc"> <div class="ts-doc-header" id="Документация"> <div class="ts-doc-heading">Документация</div> {{#if: {{{inline|}}} || {{Действия для страницы|lc={{{1}}}|nowatch=yes}} }} </div> <div class="ts-doc-content"></includeonly><noinclude> {{doc}} </noinclude> c753f0a9f65d86707cdffaf93fb49c2c52daf92b Шаблон:Музыкант/doc 10 106 209 2024-08-02T08:26:36Z wikipedia:ru>Putnik 0 /* Примеры использования */ поддержка тёмной темы wikitext text/x-wiki {{docpage}}{{OnLua|partly=1|module1=Wikidata/Interproject|module2=CategoryForProfession}} {{Установлена проверка на неизвестные параметры}} [[Википедия:Шаблоны-карточки|Шаблон-карточка]] {{tl|Музыкант}} должен присутствовать в начале статей о певцах, композиторах, дирижёрах и других музыкальных деятелях. Для музыкальных коллективов есть специальный шаблон {{tl|Музыкальный коллектив}}. == Использование == {{Parameter names example|Фон|Имя|Оригинал имени|Изображение|Ширина|Описание изображения|Имя при рождении|Полное имя|Дата рождения|Место рождения|Дата смерти|Место смерти|Похоронен|Страна|Профессии|Годы активности|Певческий голос|Инструменты|Жанры|Псевдонимы|Коллективы|Лейбл текст|Лейблы|Награды|Логотип|Ширина логотипа|Сайт}} {{Заготовка шаблона|$Оригинал имени = <nowiki>{{lang-XX|}}</nowiki>}} == Описание параметров == # <code>Фон</code> — специализация, наиболее отражающая деятельность персоналии (см. подробности в {{tl|Музыкант/цвет}}): ::: {{Легенда|#f0e68c|'''вокалист''' — вокалист}} ::: {{Легенда|#f4bf92|'''инструменталист''' — музыкант, играющий на инструментах, но не поющий}} ::: {{Легенда|#bfe0bf|'''композитор''' — музыкант, не поющий и не играющий на инструментах (синонимы: '''дирижёр''', '''продюсер''')}} # <code>Имя</code> — имя музыканта на русском языке. # <code>Оригинал имени</code> — имя на официальном языке страны рождения в формате <code><nowiki>{{lang-код языка|имя}}</nowiki></code> (для русского языка — заполнять не следует). # <code>Изображение</code> — имя файла с фотографией музыканта (см. ''[[Википедия:Иллюстрирование]]''). # <code>Ширина</code> — ширина фото (обычно нет причины это менять). # <code>Описание изображения</code> — где и когда сделано фото. Не сто́ит дублировать в этом поле имя музыканта: если о фотографии ничего не известно, просто не заполняйте это поле. # <li value=7> <code>Имя при рождении</code> — следует заполнять в случае, если имя музыканта, указанное в параметре <code>Имя</code>, не принадлежало ему с рождения. Для указания полного имени нужно использовать поле <code>Полное имя</code> (''см. ниже'').</li> # <code>Полное имя</code> — полное имя музыканта, если в поле <code>Имя</code> используется сокращённое имя. # <code>Дата рождения</code> — дата рождения музыканта в формате дд.мм.гггг — например, <code><nowiki>31.12.1945</nowiki></code>. # <code>Место рождения</code> — место рождения музыканта — например, <code><nowiki>{{МестоРождения|Лондон}}</nowiki></code>. Можно использовать шаблон {{tl|МестоРождения}}. # <code>Дата смерти</code> — дата смерти музыканта в формате дд.мм.гггг (для ныне живущих, естественно, не заполняется). О датах по старому стилю см. примечание ниже. # <code>Место смерти</code> — место смерти музыканта. Можно использовать шаблон {{tl|МестоСмерти}}. # <code>Похоронен</code> — место захоронения музыканта. # <code>Страна</code> — гражданство исполнителя; указывается просто название страны, без каких-либо шаблонов. # <code>Профессии</code> — сферы музыкальной деятельности — например, <code><nowiki>{{певец|России|XX века|XXI века}}</nowiki></code>, <code><nowiki>{{поэт|России|XX века|XXI века}}</nowiki></code> # <code>Годы активности</code> — годы активности музыканта. # <code>Певческий голос</code> — Заполняется для оперных певцов и певиц. см. [[Певческие голоса]]. # <code>Инструменты</code> — основные музыкальные инструменты (для инструменталистов). # <code>Жанры</code> — основные [[Список музыкальных жанров, направлений и стилей|жанры]], в которых пел/играл музыкант. # <code>Псевдонимы</code> — [[псевдоним]]ы, под которыми известен музыкант. # <code>Коллективы</code> — коллективы, в которых музыкант принимал участие. # <code>Лейблы</code> — названия [[Лейбл звукозаписи|лейблов]], где издавался музыкант. # <code>Награды</code> — государственные награды, имеющиеся у музыканта. # <code>Логотип</code> — личный логотип музыканта (не группы, в которую он входит). # <code>Ширина логотипа</code> — ширина логотипа (обычно нет причины это менять). # <code>Сайт</code> — ссылка на официальный сайт музыканта. === Примечания === # Незаполненные поля не отображаются при выводе шаблона. Те из них, которые в принципе не могут быть заполнены (например, <code>Певческий голос</code> для не-певцов), нужно стирать. # Если возникла необходимость изменить стандартные размеры фотографии, используйте параметр <code>Ширина</code>. Например, <code>{{nobr|1=Ширина = 250пкс}}</code>. Не рекомендуется использовать значения выше 300 # Шаблон автоматически добавляет включающую его статью в категории «{{cl|Музыканты по алфавиту}}» и «{{cl|Персоналии по алфавиту}}». # Если в статье речь идёт об анонимном музыканте, известном только под псевдонимом, то в поля <code>Имя</code> записывается псевдоним. # {{Старый-новый стиль,примечание}} == Примеры использования == {| style="background: transparent; color: inherit" |- valign="top" | {{Музыкант | Имя = Иоганн Себастьян Бах | Оригинал имени = {{lang-de|Johann Sebastian Bach}} | Изображение = JSBach.jpg | Описание изображения = Портрет Баха (1748) | Фон = композитор | Дата рождения = 21.03.1685 | Место рождения = [[Айзенах]] | Дата смерти = 28.07.1750 | Место смерти = [[Лейпциг]] | Страна = {{Флагификация|Германия}} | Профессии = [[композитор]], [[органист]] | Инструменты = [[Орган (музыкальный инструмент)|орга́н]] | Жанры = [[классическая музыка]] }} | {{Музыкант | Имя = Джон Андерсон | Оригинал имени = {{lang-en|Jon Anderson}} | Изображение = Jon anderson 1977.jpg | Описание изображения = На концерте [[Yes (группа)|Yes]] в [[Индианаполис]]е ([[1977 в музыке|1977]]) | Фон = вокалист | Полное имя = Джон Рой Андерсон | Дата рождения = 25.10.1944 | Место рождения = [[Аккрингтон]], [[Ланкашир]], [[Англия]] | Страна = {{Флагификация|Великобритания}} | Профессии = [[певец]], [[музыкант]] | Жанры = [[прогрессивный рок]], [[нью-эйдж]] | Коллективы = [[Yes (группа)|Yes]], [[Anderson Bruford Wakeman Howe|ABWH]], [[Jon & Vangelis]] | Сайт = jonanderson.com }} | {{Музыкант | Имя = Джимми Пэйдж | Оригинал имени = {{lang-en|Jimmy Page}} | Изображение = Джимми Пэйдж.jpg | Фон = инструменталист | Полное имя = James Patrick Page | Дата рождения = 09.01.1944 | Место рождения = Хестон, [[Лондон]], [[Англия]] | Страна = {{Флагификация|Великобритания}} | Профессии = * [[Гитарист]] * [[Музыкальный продюсер|продюсер]] | Инструменты = [[Gibson Les Paul]] * [[Gibson EDS-1275]] * [[Danelectro 59 DC]] * [[Fender Telecaster]] | Жанры = * [[хард-рок]] * [[блюз-рок]] * [[фолк-рок]] * [[Прогрессивный рок|прогрессив]] * [[хэви-метал]] | Псевдонимы = ZoSo | Коллективы = * [[The Yardbirds]] * [[Led Zeppelin]] * [[The Honeydrippers]] * [[The Firm]] * [[Coverdale-Page]] * [[Page and Plant]] * [[XYZ (группа)|XYZ]] | Лейблы = * [[Swan Song]] * [[Atlantic Records]] | Сайт = jimmypageonline.com }} |} == TemplateData == <templatedata> { "description": "Карточка для статей о певцах, композиторах, дирижёрах и других музыкальных деятелях", "params": { "Страна": { "label": "Страна", "description": "Гражданство музыканта. Указывается просто название страны, без каких-либо шаблонов; если стран несколько, они перечисляются через запятую. Может подставляться из Викиданных.", "type": "content" }, "Фон": { "label": "Фон", "description": "Цвет фона карточки. Допустимые значения: «вокалист» — вокалист; «инструменталист» — музыкант, играющий на инструментах, но не поющий; «композитор» — музыкант, не поющий и не играющий на инструментах (синонимы: «дирижёр», «продюсер»).", "type": "line", "suggestedvalues": [ "вокалист", "инструменталист", "композитор", "дирижёр", "продюсер" ] }, "Имя": { "label": "Имя", "description": "Имя музыканта на русском языке. Если в статье речь идёт об анонимном музыканте, известном только под псевдонимом, то в поля «Имя» записывается псевдоним.", "type": "string", "default": "Название страницы", "required": true }, "Оригинал имени": { "label": "Оригинал имени", "description": "Имя музыканта на официальном языке страны рождения, если отличается от языка в заголовке карточки. Оборачивается в один из языковых шаблонов {{lang-XX}}.", "example": "{{lang-de|Johann Sebastian Bach}}", "type": "content" }, "Изображение": { "label": "Изображение", "description": "Имя файла с фотографией музыканта. Может подставляться из Викиданных.", "type": "wiki-file-name" }, "Ширина": { "label": "Ширина", "description": "Ширина изображения. Не рекомендуется использовать значения выше 300.", "type": "number" }, "Описание изображения": { "label": "Описание изображения", "description": "Подпись к изображению, например где и когда сделано фото.", "type": "line" }, "Имя при рождении": { "label": "Имя при рождении", "description": "Следует заполнять в случае, если имя музыканта, указанное в параметре «Имя», не принадлежало ему с рождения.", "type": "content" }, "Полное имя": { "label": "Полное имя", "description": "Полное имя музыканта, если в поле «Имя» используется сокращённое имя.", "type": "content" }, "Дата рождения": { "label": "Дата рождения", "description": "Дата рождения музыканта в формате дд.мм.гггг, например 31.12.1945. Может подставляться из Викиданных. О датах по старому стилю см. примечание ниже.", "type": "date" }, "Дата смерти": { "label": "Дата смерти", "description": "Дата смерти музыканта в формате дд.мм.гггг (для ныне живущих, естественно, не заполняется). Может подставляться из Викиданных.", "type": "date" }, "Место рождения": { "label": "Место рождения", "description": "Место рождения музыканта — например, {{Место рождения|Лондон}}. Можно использовать шаблон {{МестоРождения}}. Может подставляться из Викиданных.", "type": "content" }, "Место смерти": { "label": "Место смерти", "description": "Место смерти музыканта. Можно использовать шаблон {{МестоСмерти}}. Может подставляться из Викиданных.", "type": "content" }, "Профессии": { "label": "Профессии", "description": "Сферы музыкальной деятельности — например, {{певец|России|XX века|XXI века}}, {{поэт|России|XX века|XXI века}}. Может подставляться из Викиданных.", "type": "content" }, "Годы активности": { "label": "Годы активности", "description": " Годы активности музыканта.", "type": "string", "example": "1999—2005, 2006 — {{нв}}" }, "Певческий голос": { "label": "Певческий голос", "description": "Заполняется для оперных певцов и певиц.", "type": "content" }, "Инструменты": { "label": "Инструменты", "description": "Основные музыкальные инструменты (для инструменталистов).", "type": "content" }, "Жанры": { "label": "Жанры", "description": "Основные жанры, в которых пел/играл музыкант.", "type": "content" }, "Псевдонимы": { "label": "Псевдонимы", "description": "Псевдонимы, под которыми известен музыкант.", "type": "content" }, "Коллективы": { "label": "Коллективы", "description": "Коллективы, в которых музыкант принимал участие.", "type": "content" }, "Лейбл текст": { "label": "Лейбл текст", "description": "Подменяет название строки «Лейблы» на указанное.", "type": "string" }, "Лейблы": { "label": "Лейблы", "description": "Названия лейблов, где издавался музыкант.", "type": "string" }, "Награды": { "label": "Награды", "description": "Государственные награды, имеющиеся у музыканта.", "type": "unbalanced-wikitext" }, "Логотип": { "label": "Логотип", "description": "Имя файла с логотипом музыканта (не группы, в которую он входит). Может подставляться из Викиданных.", "type": "wiki-file-name" }, "Ширина логотипа": { "label": "Ширина логотипа", "description": "Ширина логотипа. Не рекомендуется использовать значения выше 300.", "type": "number" }, "Сайт": { "label": "Сайт", "description": "Ссылка на официальный сайт музыканта. Может подставляться из Викиданных.", "type": "url" }, "Викисклад": { "label": "Викисклад", "description": "Ссылка на категорию о музыканте на Викискладе. Может подставляться из Викиданных.", "type": "line", "deprecated": "Заполняется автоматически из Викиданных" }, "Викитека": { "label": "Викитека", "type": "string", "deprecated": "Заполнятся автоматически из Викиданных" }, "Похоронен": { "description": "Место, где похоронен музыкант.", "type": "line" }, "from": { "type": "line" }, "nocat": { "type": "boolean", "autovalue": "1" } }, "format": "{{_\n| ________________ = _\n}}\n", "paramOrder": [ "Фон", "Имя", "Оригинал имени", "Изображение", "Ширина", "Описание изображения", "Имя при рождении", "Полное имя", "Дата рождения", "Место рождения", "Дата смерти", "Место смерти", "Похоронен", "Страна", "Профессии", "Годы активности", "Певческий голос", "Инструменты", "Жанры", "Псевдонимы", "Коллективы", "Лейбл текст", "Лейблы", "Награды", "Логотип", "Ширина логотипа", "Сайт", "Викисклад", "Викитека", "from", "nocat" ] } </templatedata> == См. также == * {{tl|Музыкальный коллектив}} * {{tl|Навигационная таблица музыкального исполнителя}} * {{cl|Шаблоны-карточки:Личности|1}} <includeonly> [[Категория:Шаблоны:Музыканты]] [[Категория:Шаблоны-карточки:Профессии культуры и искусства]] [[Категория:Шаблоны-карточки:Музыка]] </includeonly> 14ba03f3c4d9c6ee2c17a8274508fb62ce0dfa32 Шаблон:Doc/styles.css 10 84 165 2024-08-05T07:09:06Z wikipedia:ru>Putnik 0 исправление кода для тёмной темы ([[phab:T369874]]) text text/plain .ts-doc-doc { background-color: var(--background-color-progressive-subtle, #eaf3ff); border: 1px solid var(--border-color-content-added, #afb6e9); clear: both; margin-top: 1em; } /* Ctrl+F ":target" in [[MediaWiki:Common.css]] */ .ts-doc-doc sup.reference:target, .ts-doc-doc ol.references li:target, .ts-doc-doc .highlight-target:target, .ts-doc-doc cite:target, .ts-doc-doc span.citation:target { background: var(--ruwiki-background-color-blue200, #cfe3ff); } .ts-doc-header { align-items: center; background: var(--ruwiki-background-color-blue200, #cfe3ff); display: flex; flex-wrap: wrap; padding: .642857em 1em .5em; overflow: hidden; } .ts-doc-header .ts-tlinks-tlinks { margin-left: auto; } .ts-doc-content { padding: .214286em 1em; } .ts-doc-content:after { content: ''; clear: both; display: block; } .ts-doc-heading { display: inline-block; padding-left: 2em; background: url(//upload.wikimedia.org/wikipedia/commons/c/ca/OOjs_UI_icon_info.svg) center left no-repeat; background-size: contain; font-size: small; min-height: 1.75em; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; } @media screen { html.skin-theme-clientpref-night .ts-doc-heading { background-image: url(//upload.wikimedia.org/wikipedia/commons/c/c0/OOjs_UI_icon_info-invert.svg); } } @media screen and (prefers-color-scheme: dark) { html.skin-theme-clientpref-os .ts-doc-heading { background-image: url(//upload.wikimedia.org/wikipedia/commons/c/c0/OOjs_UI_icon_info-invert.svg); } } .ts-doc-content > *:first-child, .ts-doc-footer > *:first-child { margin-top: .5em; } .ts-doc-content > *:last-child, .ts-doc-footer > *:last-child { margin-bottom: .5em; } .ts-doc-footer { background-color: var(--background-color-progressive-subtle, #eaf3ff); border: 1px solid var(--border-color-content-added, #afb6e9); padding: .214286em 1em; margin-top: .214286em; margin-bottom: .214286em; font-style: italic; } @media (max-width: 719px) { .ts-doc-header { display: block; } .ts-doc-header .ts-tlinks-tlinks { float: none; } } /* [[Категория:Шаблоны:Подстраницы CSS]] */ be8d912472a37a6051bee114da86f913839e7ca0 Шаблон:Цвет/Инструменталист.css 10 97 191 2024-08-19T15:46:13Z wikipedia:ru>Putnik 0 поддержка тёмной темы — выбран цвет, имеющий контрастность выше 4.5 с #6d8af2, цветом ссылок на сайт и Викисклад; в связи с этим ограничения для Минервы больше не нужны text text/plain .infobox-above, .infobox-header, .infobox-below { background: #f4bf92; } @media screen { html.skin-theme-clientpref-night .infobox-above, html.skin-theme-clientpref-night .infobox-header, html.skin-theme-clientpref-night .infobox-below { background: #3f200f; } } @media screen and (prefers-color-scheme: dark) { html.skin-theme-clientpref-os .infobox-above, html.skin-theme-clientpref-os .infobox-header, html.skin-theme-clientpref-os .infobox-below { background: #3f200f; } } /* [[Категория:Шаблоны:Подстраницы CSS]] [[Категория:Шаблоны:Цвета по темам:Музыка|Инструменталист.css]] */ face7b56fa576807b9a51c764a3ac3b0f878ec82 Шаблон:Цвет/Вокалист.css 10 78 153 2024-08-19T15:50:07Z wikipedia:ru>Putnik 0 отодвинем цвет дальше в жёлто-зелёную гамму, чтобы было заметно отличие от [[Шаблон:Цвет/Инструменталист.css]] text text/plain .infobox-above, .infobox-header, .infobox-below { background: #f0e68c; } @media screen { html.skin-theme-clientpref-night .infobox-above, html.skin-theme-clientpref-night .infobox-header, html.skin-theme-clientpref-night .infobox-below { background: #302a00; } } @media screen and (prefers-color-scheme: dark) { html.skin-theme-clientpref-os .infobox-above, html.skin-theme-clientpref-os .infobox-header, html.skin-theme-clientpref-os .infobox-below { background: #302a00; } } /* [[Категория:Шаблоны:Подстраницы CSS]] [[Категория:Шаблоны:Цвета по темам:Музыка|Вокалист.css]] */ 2e2ee1ff27b701bb561598af95c43d81a92319bc Модуль:Message box/configuration 828 17 31 2024-08-29T15:57:44Z wikipedia:ru>Putnik 0 замена notheme на стили тёмной темы для cmbox Scribunto text/plain -------------------------------------------------------------------------------- -- Message box configuration -- -- -- -- This module contains configuration data for [[Module:Message box]]. -- -------------------------------------------------------------------------------- return { ambox = { types = { speedy = { class = 'ambox-speedy', image = 'Ambox warning pn.svg' }, delete = { class = 'ambox-delete', image = 'Stop hand nuvola.svg' }, content = { class = 'ambox-content', image = 'Emblem-important.svg' }, style = { class = 'ambox-style', image = 'Broom_icon.svg' }, move = { class = 'ambox-move', image = 'Merge-split-transwiki default.svg' }, protection = { class = 'ambox-protection', image = 'Padlock-silver-medium.svg' }, notice = { class = 'ambox-notice', image = 'Information.svg' }, good = { class = 'ambox-good', image = 'Green star boxed.svg' }, serious = { class = 'ambox-serious', image = 'Stop hand nuvola.svg' }, merge = { class = 'ambox-merge', image = 'Merge-split-transwiki default.svg' }, discussion = { class = 'ambox-discussion', image = 'Nuvola apps ksirc.png' } }, default = 'notice', allowBlankParams = {'talk', 'sect', 'date', 'issue', 'fix', 'subst', 'hidden', 'image'}, allowSmall = true, smallParam = 'left', smallClass = 'mbox-small-left', substCheck = true, classes = {'metadata', 'ambox'}, imageEmptyCell = true, imageCheckBlank = true, imageSmallSize = '20x20px', imageCellDiv = true, useCollapsibleTextFields = true, imageRightNone = true, sectionDefault = 'статья', allowMainspaceCategories = true, templateCategory = 'Шаблоны:Шаблоны-сообщения для статей', templateCategoryRequireName = true, templateErrorCategory = 'Шаблоны:Шаблоны-сообщения для статей с пропущенными параметрами', templateErrorParamsToCheck = {'issue', 'fix'}, removalNotice = '[[Help:Maintenance template removal|Learn how and when to remove this template message]]', templatestyles = 'Module:Message box/ambox.css', }, cmbox = { types = { speedy = { class = 'cmbox-speedy', image = 'Ambox warning pn.svg' }, delete = { class = 'cmbox-delete', image = 'Ambox warning pn.svg' }, content = { class = 'cmbox-content', image = 'Ambox important.svg' }, style = { class = 'cmbox-style', image = 'Edit-clear.svg' }, move = { class = 'cmbox-move', image = 'Merge-split-transwiki default.svg' }, protection = { class = 'cmbox-protection', image = 'Padlock-silver-medium.svg' }, notice = { class = 'cmbox-notice', image = 'Information icon4.svg' } }, default = 'notice', showInvalidTypeError = true, classes = {'cmbox'}, imageEmptyCell = true, useCollapsibleTextFields = true, templatestyles = 'Module:Message box/cmbox.css', }, fmbox = { types = { warning = { class = 'fmbox-warning', image = 'Ambox warning pn.svg' }, editnotice = { class = 'fmbox-editnotice', image = 'Information icon4.svg' }, system = { class = 'fmbox-system', image = 'Information icon4.svg' } }, default = 'system', showInvalidTypeError = true, classes = {'fmbox'}, imageEmptyCell = false, imageRightNone = false, useCollapsibleTextFields = true, templatestyles = 'Module:Message box/fmbox.css', }, imbox = { types = { speedy = { class = 'imbox-speedy', image = 'Ambox warning pn.svg' }, delete = { class = 'imbox-delete', image = 'Ambox warning pn.svg' }, content = { class = 'imbox-content', image = 'Ambox important.svg' }, style = { class = 'imbox-style', image = 'Edit-clear.svg' }, move = { class = 'imbox-move', image = 'Merge-split-transwiki default.svg' }, protection = { class = 'imbox-protection', image = 'Padlock-silver-medium.svg' }, license = { class = 'imbox-license licensetpl', image = 'Imbox license.png' -- @todo We need an SVG version of this }, featured = { class = 'imbox-featured', image = 'Cscr-featured.svg' }, notice = { class = 'imbox-notice', image = 'Information icon4.svg' } }, default = 'notice', showInvalidTypeError = true, classes = {'imbox'}, imageEmptyCell = true, below = true, useCollapsibleTextFields = true, templateCategory = 'Шаблоны:Шаблоны-сообщения для файлов', templatestyles = 'Module:Message box/imbox.css', }, ombox = { types = { speedy = { class = 'ombox-speedy', image = 'OOjs UI icon alert-destructive.svg' }, delete = { class = 'ombox-delete', image = 'OOjs UI icon alert-destructive.svg' }, content = { class = 'ombox-content', image = 'OOjs UI icon notice-warning.svg' }, style = { class = 'ombox-style', image = 'Edit-clear.svg' }, move = { class = 'ombox-move', image = 'Imbox move.png' }, protection = { class = 'ombox-protection', image = 'Imbox protection.png' }, notice = { class = 'ombox-notice', image = 'OOjs UI icon info-progressive.svg' } }, default = 'notice', showInvalidTypeError = true, classes = {'ombox'}, allowSmall = true, imageEmptyCell = true, imageRightNone = true, useCollapsibleTextFields = true, templatestyles = 'Module:Message box/ombox.css', }, tmbox = { types = { speedy = { class = 'tmbox-speedy', image = 'Ambox warning pn.svg' }, delete = { class = 'tmbox-delete', image = 'Ambox warning pn.svg' }, content = { class = 'tmbox-content', image = 'Ambox important.svg' }, style = { class = 'tmbox-style', image = 'Edit-clear.svg' }, move = { class = 'tmbox-move', image = 'Merge-split-transwiki default.svg' }, protection = { class = 'tmbox-protection', image = 'Padlock-silver-medium.svg' }, notice = { class = 'tmbox-notice', image = 'Information icon4.svg' } }, default = 'notice', showInvalidTypeError = true, classes = {'tmbox'}, allowSmall = true, imageRightNone = true, imageEmptyCell = true, imageEmptyCellStyle = true, useCollapsibleTextFields = true, templateCategory = 'Шаблоны:Шаблоны-сообщения для страниц обсуждений', templatestyles = 'Module:Message box/tmbox.css', } } 2c0750ec1561e8ec25c0988c411f3c69e4957483 Модуль:Check for unknown parameters 828 9 15 2024-09-19T19:18:15Z wikipedia:ru>Stjn 0 поддержка тёмной темы Scribunto text/plain -- This module may be used to compare the arguments passed to the parent -- with a list of arguments, returning a specified result if an argument is -- not on the list local p = {} local function trim(s) return s:match('^%s*(.-)%s*$') end local function isnotempty(s) return s and trim(s) ~= '' end function p.check (frame) local args = frame.args local pargs = frame:getParent().args local ignoreblank = isnotempty(frame.args['ignoreblank']) local showblankpos = isnotempty(frame.args['showblankpositional']) local knownargs = {} local unknown = frame.args['unknown'] or 'Found _VALUE_, ' local preview = frame.args['preview'] local values = {} local res = {} local regexps = {} -- create the list of known args, regular expressions, and the return string for k, v in pairs(args) do if type(k) == 'number' then v = trim(v) knownargs[v] = 1 elseif k:find('^regexp[1-9][0-9]*$') then table.insert(regexps, '^' .. v .. '$') end end if isnotempty(preview) then preview = '<div class="hatnote" style="color: var(--color-error, #d73333)"><strong>Предупреждение:</strong> ' .. preview .. ' (это сообщение видно только при предпросмотре страницы).</div>' elseif preview == nil then preview = unknown end -- loop over the parent args, and make sure they are on the list for k, v in pairs(pargs) do if type(k) == 'string' and knownargs[k] == nil then local knownflag = false for i, regexp in ipairs(regexps) do if mw.ustring.match(k, regexp) then knownflag = true break end end if not knownflag and ( not ignoreblank or isnotempty(v) ) then k = mw.ustring.gsub(k, '[^%w\-_ ]', '?') table.insert(values, k) end elseif type(k) == 'number' and knownargs[tostring(k)] == nil and ( showblankpos or isnotempty(v) ) then local vlen = mw.ustring.len(v) v = mw.ustring.sub(v, 1, (vlen < 25) and vlen or 25) v = mw.ustring.gsub(v, '[^%w\-_ ]', '?') table.insert(values, k .. ' = ' .. v .. ((vlen >= 25) and ' ...' or '')) end end -- add resuls to the output tables if #values > 0 then if frame:preprocess( "{{REVISIONID}}" ) == "" then unknown = preview end for k, v in pairs(values) do if v == '' then -- Fix odd bug for | = which gets stripped to the empty string and -- breaks category links v = ' ' end local r = unknown:gsub('_VALUE_', v) table.insert(res, r) end end return table.concat(res) end function p.generate (frame) local res = '{{#invoke:check for unknown parameters|check\n' .. '|unknown=' .. frame.args['unknown'] .. '\n' local checkerparams = {'ignoreblank', 'preview', 'showblankpositional'} for _, v in pairs(checkerparams) do if frame.args[v] then res = res .. '|' .. v .. '=' .. frame.args[v] .. '\n' end end local templatenamespace = frame.args[1] local templatetitle = frame.args[2] local pagepointer = mw.title.new(templatetitle, templatenamespace) -- именно такой порядок! local text = pagepointer.getContent(pagepointer) local params = {} for param in string.gmatch(text, '\{\{\{([^\|\}]*)') do params[#params+1] = mw.text.trim(param) end table.sort(params) for k, v in pairs(params) do if k == 1 or v ~= params[k-1] then res = res .. '|' .. v end end res = res .. '}}' return res end return p 9da4c0ae23797bb024279d7544e897ae3f2bbf43 Шаблон:Docpage 10 93 183 2024-09-25T09:40:06Z wikipedia:ru>Stjn 0 __EXPECTED_UNCONNECTED_PAGE__ wikitext text/x-wiki <includeonly>{{#ifeq: {{SUBPAGENAME}} | doc | {{fmbox | class = hlist nowraplinks | style = margin-bottom:1em; background:var(--background-color-progressive-subtle, #eaf3ff); color:inherit; border:1px solid var(--border-color-content-added, #a3d3ff); | image = [[Файл:OOjs UI icon info.svg|24px|link=|alt=|class=skin-invert-image]] | text = <div> * [[:{{#titleparts: {{SUBJECTPAGENAME}} | -1 }}]] * [[:{{SUBJECTPAGENAME}}|Документация]] * [[{{#titleparts: {{TALKPAGENAME}} | -1 }}|Обсуждение]] * [[Служебная:Whatlinkshere/{{#titleparts: {{SUBJECTPAGENAME}} | -1 }}|Где используется]] {{#ifeq: {{NAMESPACE}} | {{ns:Template}} | ** {{Параметры шаблона|{{#titleparts: {{PAGENAME}} | -1 }}}} }}</div><!-- -->{{#if: {{{nocat|}}} || {{#ifexist: {{NAMESPACE}}:{{BASEPAGENAME}} || [[Категория:Шаблоны:Документация несуществующих шаблонов]] }} }} }}{{#if: {{{nocat|}}} || {{#ifeq: {{NAMESPACE}} | Модуль | [[Категория:Модули:Документация]] | [[Категория:Шаблоны:Документация]] }}__EXPECTED_UNCONNECTED_PAGE__ }} }}</includeonly><noinclude>{{doc}}</noinclude> e2d07566c50be35ac409e8396893a3b9d8676e0c Шаблон:Вложенные кавычки 10 89 175 2024-10-12T20:37:27Z wikipedia:ru>Stjn 0 перевод на [[модуль:Вложенные кавычки]] wikitext text/x-wiki {{safesubst:<noinclude />#invoke:Вложенные кавычки|main}}<noinclude> {{doc}} </noinclude> 9ad9d29329e774649043f48fba384679babb4c08 Модуль:Вложенные кавычки 828 113 223 2024-10-12T23:33:31Z wikipedia:ru>Stjn 0 require( 'strict' ) Scribunto text/plain -- -- Re-implement [[Template:Вложенные кавычки]] in Lua -- Replaces «» to „“ without touching links -- require( 'strict' ) local getArgs local p = {} local function isEmpty( str ) return str == nil or str == '' end local function protectLinks( str ) local links, head = {}, 0 while true do local s, e, link = str:find( '(%[%[.-%]%])', head ) if not link then return str, links elseif link:find( '[[', 3, true ) then head = s + 2 else -- If the alt text contains '[', it can have one final ']'. if link:match( '^[^|]*|.-%[', 3 ) and str:sub( e + 1, e + 1 ) == ']' then link = link .. ']' end table.insert( links, link ) local placeholder = mw.ustring.char( 0xF0000 + #links ) str = str:gsub( link:gsub( '[$%%()*+%-.?[%]^]', '%%%0' ), placeholder ) head = str:find( placeholder ) + 1 end end end local function unprotectLinks( str, links ) for i, link in ipairs( links ) do str = str:gsub( mw.ustring.char( 0xF0000 + i ), link:gsub( '%%', '%%%%' ), 1 ) end return str end local function replace( str ) if isEmpty( str ) then return '' end str = mw.ustring.gsub( str, '«(.[^«»]-)»', '„%1“' ) return str end function p._main( text ) if isEmpty( text ) then return '' end local links = {} text, links = protectLinks( text ) if #links == 0 then return replace( text ) end -- Replace visible link text while keeping links intact for i, link in ipairs( links ) do local linkTarget = mw.text.trim( link, '%[%]' ) local linkText = '' local pipePos = link:find( '|', 1, true ) if pipePos ~= nil then local parts = mw.text.split( linkTarget, '|' ) linkTarget = parts[ 1 ] linkText = replace( parts[ 2 ] ) else linkText = replace( linkTarget ) end links[ i ] = string.format( '[[%s|%s]]', linkTarget, linkText ) end text = replace( text ) text = unprotectLinks( text, links ) return text end function p.main( frame ) getArgs = require( 'Module:Arguments' ).getArgs local args = getArgs( frame ) return p._main( args[ 1 ] ) end return p e7cf7cd583a5fa189c85ccf455feebd48aa60fa0 Модуль:Wikidata 828 31 59 2024-10-26T15:17:47Z wikipedia:ru>Stjn 0 [[ВП:×|отмена]]: сломало отображение в множестве статей Scribunto text/plain ---settings, may differ from project to project local fileDefaultSize = '267x400px' local outputReferences = true local writingSystemElementId = 'Q8209' local langElementId = 'Q7737' ---Ссылки на используемые модули, которые потребуются в 99% случаев загрузки страниц (чтобы иметь на виду при переименовании) local moduleSources = require( 'Module:Sources' ) local WDS = require( 'Module:WikidataSelectors' ) ---Константы ---@type string local CONTENT_LANGUAGE_CODE = mw.language.getContentLanguage():getCode() local p = {} local g_config, g_frame local formatDatavalue, formatEntityId, formatRefs, formatSnak, formatStatement, formatStatementDefault, getSourcingCircumstances, getPropertyParams ---@param obj table ---@param target table ---@param skipEmpty boolean | nil ---@return table local function copyTo( obj, target, skipEmpty ) for key, val in pairs( obj ) do if skipEmpty ~= true or ( val ~= nil and val ~= '' ) then target[ key ] = val end end return target end ---@param prev number | nil ---@param next number | nil ---@return number | nil local function min( prev, next ) if prev == nil or prev > next then return next end return prev end ---@param prev number | nil ---@param next number | nil ---@return number | nil local function max( prev, next ) if prev == nil or prev < next then return next end return prev end ---@param section string ---@param code string ---@return any | nil local function getConfig( section, code ) if g_config == nil then g_config = require( 'Module:Wikidata/config' ) end if not g_config then g_config = {} end if not section then return g_config end if not code then return g_config[ section ] or {} end if not g_config[ section ] then return nil end return g_config[ section ][ code ] end ---@param code string ---@param sortKey string | nil ---@return string local function getCategoryByCode( code, sortKey ) local value = getConfig( 'categories', code ) if not value or value == '' then return '' end if sortKey ~= nil then return '[[Category:' .. value .. '|' .. sortKey .. ']]'; -- экранировать? else return '[[Category:' .. value .. ']]' end end ---@param isoStr string | table ---@return table | nil local function splitISO8601( isoStr ) if 'table' == type( isoStr ) then if isoStr.args and isoStr.args[ 1 ] then isoStr = '' .. isoStr.args[ 1 ] else return 'unknown argument type: ' .. type( isoStr ) .. ': ' .. table.tostring( isoStr ) end end local Y, M, D = ( function( str ) local pattern = "(%-?%d+)%-(%d+)%-(%d+)T" local _Y, _M, _D = mw.ustring.match( str, pattern ) return tonumber( _Y ), tonumber( _M ), tonumber( _D ) end )( isoStr ) local h, m, s = ( function( str ) local pattern = "T(%d+):(%d+):(%d+)%Z" local _H, _M, _S = mw.ustring.match( str, pattern ) return tonumber( _H ), tonumber( _M ), tonumber( _S ) end )( isoStr ) local oh, om = ( function( str ) if str:sub(-1) == "Z" then -- ends with Z, Zulu time return 0, 0 end -- matches ±hh:mm, ±hhmm or ±hh; else returns nils local pattern = "([-+])(%d%d):?(%d?%d?)$" local sign, oh, om = mw.ustring.match( str, pattern ) sign, oh, om = sign or "+", oh or "00", om or "00" return tonumber( sign .. oh ), tonumber( sign .. om ) end )( isoStr ) return { year=Y, month=M, day=D, hour=( h + oh ), min=( m + om ), sec=s } end ---Внутренняя функции для получения границ временного диапазона ---@param time string ---@param precision number ---@return table | nil function p._parseTimeBoundaries( time, precision ) local s = splitISO8601( time ) if not s then return nil end if precision >= 0 and precision <= 8 then local powers = { 1000000000 , 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10 } local power = powers[ precision + 1 ] local left = s.year - ( s.year % power ) return { tonumber( os.time( { year=left, month=1, day=1, hour=0, min=0, sec=0 } ) ) * 1000, tonumber( os.time( { year=left + power - 1, month=12, day=31, hour=29, min=59, sec=58 } ) ) * 1000 + 1999 } end if precision == 9 then return { tonumber( os.time( { year=s.year, month=1, day=1, hour=0, min=0, sec=0} )) * 1000, tonumber( os.time( { year=s.year, month=12, day=31, hour=23, min=59, sec=58} )) * 1000 + 1999 } end if precision == 10 then local lastDays = { 31, 28.25, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } local lastDay = lastDays[ s.month ] return { tonumber( os.time( { year=s.year, month=s.month, day=1, hour=0, min=0, sec=0 } ) ) * 1000, tonumber( os.time( { year=s.year, month=s.month, day=lastDay, hour=23, min=59, sec=58 } ) ) * 1000 + 1999 } end if precision == 11 then return { tonumber( os.time( { year=s.year, month=s.month, day=s.day, hour=0, min=0, sec=0 } ) ) * 1000, tonumber( os.time( { year=s.year, month=s.month, day=s.day, hour=23, min=59, sec=58 } ) ) * 1000 + 1999 } end if precision == 12 then return { tonumber( os.time( { year=s.year, month=s.month, day=s.day, hour=s.hour, min=0, sec=0 } ) ) * 1000, tonumber( os.time( { year=s.year, month=s.month, day=s.day, hour=s.hour, min=59, sec=58 } ) ) * 1000 + 1999 } end if precision == 13 then return { tonumber( os.time( { year=s.year, month=s.month, day=s.day, hour=s.hour, min=s.min, sec=0 } ) ) * 1000, tonumber( os.time( { year=s.year, month=s.month, day=s.day, hour=s.hour, min=s.min, sec=58 } ) ) * 1000 + 1999 } end if precision == 14 then local t = tonumber( os.time( { year=s.year, month=s.month, day=s.day, hour=s.hour, min=s.min, sec=0 } ) ) return { t * 1000, t * 1000 + 999 } end error( 'Unsupported precision: ' .. precision ) end ---Внутренняя функция для получения числового значения времени из snak'а ---@param table snak ---@return number | nil function p._parseTimeFromSnak( snak ) if snak and snak.datavalue and snak.datavalue.value and snak.datavalue.value.time then local timeData = splitISO8601( tostring( snak.datavalue.value.time ) ) timeData.month = math.max( timeData.month, 1 ) timeData.day = math.max( timeData.day, 1 ) return tonumber( os.time( timeData ) ) * 1000 end return nil end ---Функция для формирования категории на основе wikidata/config ---@param options table ---@param entityId string ---@return string local function extractCategory( options, entityId ) if not entityId or not options.category or options.nocat then return '' end if type( entityId ) ~= 'string' then entityId = entityId.id end local claims = WDS.load( entityId, options.category ) if not claims then return '' end for _, claim in pairs( claims ) do if claim and claim.mainsnak and claim.mainsnak.datavalue and claim.mainsnak.datavalue.type == 'wikibase-entityid' then local catEntityId = claim.mainsnak.datavalue.value.id local wbStatus, catSiteLink = pcall( mw.wikibase.getSitelink, catEntityId ) if wbStatus and catSiteLink then return '[[' .. catSiteLink .. ']]' end end end return '' end ---Преобразует строку в булевое значение ---@param valueToParse string ---@return boolean Преобразованное значение, если его удалось распознать, или defaultValue во всех остальных случаях local function toBoolean( valueToParse, defaultValue ) if valueToParse ~= nil then if valueToParse == false or valueToParse == '' or valueToParse == 'false' or valueToParse == '0' then return false end return true end return defaultValue end ---Обрачивает отформатированное значение в инлайновый или блочный тег. ---@param value string value ---@param attributes table of attributes ---@return string HTML tag with value local function wrapValue( value, attributes ) local tagName = 'span' local spacer = '' if string.match( value, '\n' ) or string.match( value, '<t[dhr][ >]' ) or string.match( value, '<div[ >]' ) or string.find( value, 'UNIQ%-%-imagemap' ) then tagName = 'div' spacer = '\n' end local attrString = '' for key, val in pairs( attributes or {} ) do local _key = mw.text.trim( key ) local _value = mw.text.encode( mw.text.trim( val ) ) attrString = attrString .. _key .. '="' .. _value .. '" ' end return '<' .. tagName .. ' ' .. attrString .. '>' .. spacer .. value .. '</' .. tagName .. '>' end ---Wraps formatted snak value into HTML tag with attributes. ---@param value string value of snak ---@param hash string ---@param attributes table of extra attributes ---@return string HTML tag with value local function wrapSnak( value, hash, attributes ) local newAttributes = mw.clone( attributes or {} ) newAttributes[ 'class' ] = ( newAttributes[ 'class' ] or '' ) .. ' wikidata-snak' if hash then newAttributes[ 'data-wikidata-hash'] = hash else newAttributes[ 'class' ] = newAttributes[ 'class' ] .. ' wikidata-main-snak' end return wrapValue( value, newAttributes ) end ---Wraps formatted statement value into HTML tag with attributes. ---@param value string value of statement ---@param propertyId string PID of property ---@param claimId string ID of claim or nil for local value ---@param attributes table of extra attributes ---@return string HTML tag with value local function wrapStatement( value, propertyId, claimId, attributes ) local newAttributes = mw.clone( attributes or {} ) newAttributes[ 'class' ] = newAttributes[ 'class' ] or '' newAttributes[ 'data-wikidata-property-id' ] = string.upper( propertyId ) if claimId then newAttributes[ 'class' ] = newAttributes[ 'class' ] .. ' wikidata-claim' newAttributes[ 'data-wikidata-claim-id' ] = claimId else newAttributes[ 'class' ] = newAttributes[ 'class' ] .. ' no-wikidata' end return wrapValue( value, newAttributes ) end ---Wraps formatted qualifier's statement value into HTML tag with attributes. ---@param value string value of qualifier's statement ---@param qualifierId string PID of qualifier ---@param attributes table of extra attributes ---@return string HTML tag with value local function wrapQualifier( value, qualifierId, attributes ) local newAttributes = mw.clone( attributes or {} ) newAttributes[ 'data-wikidata-qualifier-id' ] = string.upper( qualifierId ) return wrapValue( value, newAttributes ) end ---Функция для получения сущности (еntity) для текущей страницы ---Подробнее о сущностях см. d:Wikidata:Glossary/ru ---@param id string Идентификатор (типа P18, Q42) ---@return table Таблица, элементы которой индексируются с нуля local function getEntityFromId( id ) local entity local wbStatus if id then wbStatus, entity = pcall( mw.wikibase.getEntity, id ) else wbStatus, entity = pcall( mw.wikibase.getEntity ) end return entity end ---Внутренняя функция для формирования сообщения об ошибке ---@param key string Ключ элемента в таблице config.errors (например entity-not-found) ---@return void local function throwError( key ) error( getConfig( 'errors', key ) ) end ---Функция для получения идентификатора сущностей ---@param value table ---@return string local function getEntityIdFromValue( value ) local prefix = '' if value[ 'entity-type' ] == 'item' then prefix = 'Q' elseif value[ 'entity-type' ] == 'property' then prefix = 'P' else throwError( 'unknown-entity-type' ) end return prefix .. value[ 'numeric-id' ] end ---Проверка на наличие специализированной функции в опциях ---@param options table ---@param prefix string ---@return function local function getUserFunction( options, prefix, defaultFunction ) -- проверка на указание специализированных обработчиков в параметрах, -- переданных при вызове if options[ prefix .. '-module' ] or options[ prefix .. '-function' ] then -- проверка на пустые строки в параметрах или их отсутствие if not options[ prefix .. '-module' ] or not options[ prefix .. '-function' ] then throwError( 'unknown-' .. prefix .. '-module' ) end -- динамическая загруза модуля с обработчиком указанным в параметре local formatter = require( 'Module:' .. options[ prefix .. '-module' ] ) if formatter == nil then throwError( prefix .. '-module-not-found' ) end local fun = formatter[ options[ prefix .. '-function' ] ] if fun == nil then throwError( prefix .. '-function-not-found' ) end return fun end return defaultFunction end ---Выбирает свойства по property id, дополнительно фильтруя их по рангу ---@param context table ---@param options table ---@param propertySelector string ---@return table | nil local function selectClaims( context, options, propertySelector ) if not context then error( 'context not specified' ); end if not options then error( 'options not specified' ); end if not options.entityId then error( 'options.entity is missing' ); end if not propertySelector then error( 'propertySelector not specified' ); end local result = WDS.load( options.entityId, propertySelector ) if not result or #result == 0 then return nil end if options.limit and options.limit ~= '' and options.limit ~= '-' then local limit = tonumber( options.limit, 10 ) while #result > limit do table.remove( result ) end end return result end ---Функция для получения значения свойства элемента в заданный момент времени. ---@param entityId string ---@param boundaries table Временные границы ---@param propertyIds table<string> ---@param selectors table<string> ---@return table Таблица соответствующих значений свойства local function getPropertyInBoundaries( context, entityId, boundaries, propertyIds, selectors ) if type( entityId ) ~= 'string' then error( 'type of entityId argument expected string, but was ' .. type(entityId)); end local results = {} if not propertyIds or #propertyIds == 0 then return results end for i, propertyId in ipairs( propertyIds ) do local selector if selectors ~= nil then selector = selectors[ i ] or selectors[ propertyId ] or propertyId else selector = propertyId end local fakeAllClaims = {} fakeAllClaims[ propertyId ] = mw.wikibase.getAllStatements( entityId, propertyId ) local filteredClaims = WDS.filter( fakeAllClaims, selector .. '[rank:preferred, rank:normal]' ) if filteredClaims then for _, claim in pairs( filteredClaims ) do if not boundaries then if not claim.qualifiers or not claim.qualifiers.P582 then table.insert( results, claim.mainsnak ) end else local startBoundaries = p.getTimeBoundariesFromQualifier( context.frame, context, claim, 'P580' ) local endBoundaries = p.getTimeBoundariesFromQualifier( context.frame, context, claim, 'P582' ) if ( startBoundaries == nil or startBoundaries[ 1 ] <= boundaries[ 1 ] ) and ( endBoundaries == nil or endBoundaries[ 1 ] >= boundaries[ 2 ] ) then table.insert( results, claim.mainsnak ) end end end end if #results > 0 then break end end return results end ---@param context table ---@param propertyId string ---@return table | nil function p.getTimeBoundariesFromProperty( context, propertyId ) local dateClaims = WDS.filter( context.entity.claims, propertyId ) if not dateClaims or #dateClaims == 0 then return nil; end -- only support exact date so far, but need improvment local left = nil local right = nil for _, claim in pairs( dateClaims ) do if not claim.mainsnak then return nil end local boundaries = context.parseTimeBoundariesFromSnak( claim.mainsnak ) if not boundaries then return nil end left = min( left, boundaries[ 1 ] ) right = max( right, boundaries[ 2 ] ) end if not left or not right then return nil end return { left, right } end ---@param context table ---@param propertyIds table<string> ---@return table | nil function p.getTimeBoundariesFromProperties( context, propertyIds ) for _, propertyId in ipairs( propertyIds ) do local result = p.getTimeBoundariesFromProperty( context, propertyId ); if result then return result end end return nil end ---@param context table ---@param statement table ---@param qualifierId string ---@return table | nil function p.getTimeBoundariesFromQualifier( _, context, statement, qualifierId ) -- only support exact date so far, but need improvement local left, right if statement.qualifiers and statement.qualifiers[ qualifierId ] then for _, qualifier in pairs( statement.qualifiers[ qualifierId ] ) do local boundaries = context.parseTimeBoundariesFromSnak( qualifier ) if not boundaries then return nil end left = min( left, boundaries[ 1 ] ) right = max( right, boundaries[ 2 ] ) end end if not left or not right then return nil end return { left, right } end ---@param _ table ---@param context table ---@param statement table ---@param qualifierIds table<string> ---@return table | nil function p.getTimeBoundariesFromQualifiers( _, context, statement, qualifierIds ) if not qualifierIds then qualifierIds = { 'P582', 'P580', 'P585' } end for _, qualifierId in pairs( qualifierIds ) do local result = p.getTimeBoundariesFromQualifier( _, context, statement, qualifierId ) if result then return result end end return nil end ---@type table<string> local getLabelWithLang_DEFAULT_PROPERTIES = { 'P1813', 'P1448', 'P1705' } ---@type table<string> local getLabelWithLang_DEFAULT_SELECTORS = { 'P1813[language:' .. CONTENT_LANGUAGE_CODE .. '][!P282,P282:' .. writingSystemElementId .. '][!P3831,P3831:Q105690470]', 'P1448[language:' .. CONTENT_LANGUAGE_CODE .. '][!P282,P282:' .. writingSystemElementId .. '][!P3831,P3831:Q105690470]', 'P1705[language:' .. CONTENT_LANGUAGE_CODE .. '][!P282,P282:' .. writingSystemElementId .. '][!P3831,P3831:Q105690470]' } ---Функция для получения метки элемента в заданный момент времени. ---@param context table ---@param options table ---@param entityId string ---@param boundaries table ---@param propertyIds table ---@param selectors table<string> ---@return string, string Текстовая метка элемента, язык метки local function getLabelWithLang( context, options, entityId, boundaries, propertyIds, selectors ) if type( entityId ) ~= 'string' then error( 'type of entityId argument expected string, but was ' .. type( entityId ) ); end if not entityId then return nil end local langCode = CONTENT_LANGUAGE_CODE -- name from label local label if options.text and options.text ~= '' then label = options.text else if not propertyIds then propertyIds = getLabelWithLang_DEFAULT_PROPERTIES selectors = getLabelWithLang_DEFAULT_SELECTORS end -- name from properties local results = getPropertyInBoundaries( context, entityId, boundaries, propertyIds, selectors ) for _, result in pairs( results ) do if result.datavalue and result.datavalue.value then if result.datavalue.type == 'monolingualtext' and result.datavalue.value.text then label = result.datavalue.value.text langCode = result.datavalue.value.language break elseif result.datavalue.type == 'string' then label = result.datavalue.value break end end end if not label then label, langCode = mw.wikibase.getLabelWithLang( entityId ) if not langCode then return nil end end end return label, langCode end ---@param context table ---@param options table ---@return string local function formatPropertyDefault( context, options ) if not context then error( 'context not specified' ); end if not options then error( 'options not specified' ); end if not options.entityId then error( 'options.entityId missing' ); end local claims if options.property then -- TODO: Почему тут может не быть property? if options.rank then -- передать настройки ранга из конфига claims = context.selectClaims( options, options.property .. options.rank ) else claims = context.selectClaims( options, options.property ) end end if claims == nil then return '' --TODO error? end -- Обход всех заявлений утверждения и с накоплением оформленных предпочтительных -- заявлений в таблице local formattedClaims = {} for _, claim in pairs( claims ) do local formattedStatement = context.formatStatement( options, claim ) -- здесь может вернуться либо оформленный текст заявления, либо строка ошибки, либо nil if formattedStatement and formattedStatement ~= '' then if not options.plain then formattedStatement = context.wrapStatement( formattedStatement, options.property, claim.id ) end table.insert( formattedClaims, formattedStatement ) end end -- создание текстовой строки со списком оформленых заявлений из таблицы local out = mw.text.listToText( formattedClaims, options.separator, options.conjunction ) if out ~= '' then if options.before then out = options.before .. out end if options.after then out = out .. options.after end end return out end ---Create context ---@param initOptions table ---@return table | nil local function initContext( initOptions ) local context = { entityId = initOptions.entityId, entity = initOptions.entity, extractCategory = extractCategory, formatSnak = formatSnak, formatPropertyDefault = formatPropertyDefault, formatStatementDefault = formatStatementDefault, getPropertyInBoundaries = getPropertyInBoundaries, getTimeBoundariesFromProperty = p.getTimeBoundariesFromProperty, getTimeBoundariesFromProperties = p.getTimeBoundariesFromProperties, getTimeBoundariesFromQualifier = p.getTimeBoundariesFromQualifier, getTimeBoundariesFromQualifiers = p.getTimeBoundariesFromQualifiers, parseTimeFromSnak = p._parseTimeFromSnak, getLabelWithLang = getLabelWithLang, wrapSnak = wrapSnak, wrapStatement = wrapStatement, wrapQualifier = wrapQualifier, } context.cloneOptions = function( options ) local entity = options.entity options.entity = nil local newOptions = mw.clone( options ) options.entity = entity newOptions.entity = entity newOptions.frame = options.frame; -- На склонированном фрейме frame:expandTemplate() return newOptions end context.formatProperty = function( options ) local func = getUserFunction( options, 'property', context.formatPropertyDefault ) return func( context, options ) end context.formatStatement = function( options, statement ) return formatStatement( context, options, statement ) end context.formatSnak = function( options, snak, circumstances ) return formatSnak( context, options, snak, circumstances ) end context.formatRefs = function( options, statement ) return formatRefs( context, options, statement ) end context.parseTimeBoundariesFromSnak = function( snak ) if snak and snak.datavalue and snak.datavalue.value and snak.datavalue.value.time and snak.datavalue.value.precision then return p._parseTimeBoundaries( snak.datavalue.value.time, snak.datavalue.value.precision ) end return nil end context.getSourcingCircumstances = function( statement ) return getSourcingCircumstances( statement ) end context.selectClaims = function( options, propertyId ) return selectClaims( context, options, propertyId ) end return context end ---Функция для оформления утверждений (statement) ---Подробнее о утверждениях см. d:Wikidata:Glossary/ru ---@param options table ---@return string Formatted wikitext. local function formatProperty( options ) -- Получение сущности по идентификатору local entity = getEntityFromId( options.entityId ) if not entity then return -- throwError( 'entity-not-found' ) end -- проверка на присутсвие у сущности заявлений (claim) -- подробнее о заявлениях см. d:Викиданные:Глоссарий if not entity.claims then return '' --TODO error? end -- improve options options.frame = g_frame options.entity = entity options.extends = function( self, newOptions ) return copyTo( newOptions, copyTo( self, {} ) ) end if options.i18n then options.i18n = copyTo( options.i18n, copyTo( getConfig( 'i18n' ), {} ) ) else options.i18n = getConfig( 'i18n' ) end local context = initContext( options ) return context.formatProperty( options ) end ---Функция для оформления одного утверждения (statement) ---@param context table ---@param options table ---@param statement table ---@return string Formatted wikitext. function formatStatement( context, options, statement ) if not statement then error( 'statement is not specified or nil' ) end if not statement.type or statement.type ~= 'statement' then throwError( 'unknown-claim-type' ) end local functionToCall = getUserFunction( options, 'claim', context.formatStatementDefault ) return functionToCall( context, options, statement ) end ---@param statement table ---@return table function getSourcingCircumstances( statement ) if not statement then error( 'statement is not specified' ) end local circumstances = {} if statement.qualifiers and statement.qualifiers.P1480 then for _, qualifier in pairs( statement.qualifiers.P1480 ) do if qualifier and qualifier.datavalue and qualifier.datavalue.type == 'wikibase-entityid' and qualifier.datavalue.value and qualifier.datavalue.value[ 'entity-type'] == 'item' then table.insert( circumstances, qualifier.datavalue.value.id ) end end end return circumstances end ---Функция для оформления одного утверждения (statement) ---@param context table Context. ---@param options table Parameters. ---@param statement table ---@return string Formatted wikitext. function formatStatementDefault( context, options, statement ) if not context then error( 'context is not specified' ) end if not options then error( 'options is not specified' ) end if not statement then error( 'statement is not specified' ) end local circumstances = context.getSourcingCircumstances( statement ) options.qualifiers = statement.qualifiers local result = context.formatSnak( options, statement.mainsnak, circumstances ) if options.qualifier and statement.qualifiers and statement.qualifiers[ options.qualifier ] then local qualifierConfig = getPropertyParams( options.qualifier, nil, {} ) if options.i18n then qualifierConfig.i18n = options.i18n end if qualifierConfig.datatype == 'time' then qualifierConfig.nolinks = true end local qualifierValues = {} for _, qualifierSnak in pairs( statement.qualifiers[ options.qualifier ] ) do local snakValue = context.formatSnak( qualifierConfig, qualifierSnak ) if snakValue and snakValue ~= '' then table.insert( qualifierValues, snakValue ) end end if result and result ~= '' and #qualifierValues then if qualifierConfig.invisible then result = result .. table.concat( qualifierValues, ', ' ) else result = result .. ' (' .. table.concat( qualifierValues, ', ' ) .. ')' end end end if result and result ~= '' and options.references then result = result .. context.formatRefs( options, statement ) end return result end ---Функция для оформления части утверждения (snak) ---Подробнее о snak см. d:Викиданные:Глоссарий ---@param context table Context. ---@param options table Parameters. ---@param snak table ---@param circumstances table ---@return string Formatted wikitext. function formatSnak( context, options, snak, circumstances ) circumstances = circumstances or {} local result if snak.snaktype == 'somevalue' then if options[ 'somevalue' ] and options[ 'somevalue' ] ~= '' then result = options[ 'somevalue' ] else result = options.i18n[ 'somevalue' ] end elseif snak.snaktype == 'novalue' then if options[ 'novalue' ] and options[ 'novalue' ] ~= '' then result = options[ 'novalue' ] else result = options.i18n[ 'novalue' ] end elseif snak.snaktype == 'value' then result = formatDatavalue( context, options, snak.datavalue, snak.datatype ) for _, item in pairs( circumstances ) do if options.i18n[ item ] then result = options.i18n[ item ] .. result end end else throwError( 'unknown-snak-type' ) end if not result or result == '' then return nil end if options.plain then return result end return context.wrapSnak( result, snak.hash ) end ---Функция для оформления объектов-значений с географическими координатами ---@param value string Raw value. ---@param options table Parameters. ---@return string Formatted string. local function formatGlobeCoordinate( value, options ) -- проверка на требование в параметрах вызова на возврат сырого значения if options[ 'subvalue' ] == 'latitude' then -- широты return value[ 'latitude' ] elseif options[ 'subvalue' ] == 'longitude' then -- долготы return value[ 'longitude' ] elseif options[ 'nocoord' ] and options[ 'nocoord' ] ~= '' then -- если передан параметр nocoord, то не выводить координаты -- обычно это делается при использовании нескольких карточек на странице return '' else -- в противном случае формируются параметры для вызова шаблона {{coord}} -- нужно дописать в документации шаблона, что он отсюда вызывается, и что -- любое изменние его парамеров должно быть согласовано с кодом тут local coordModule = require( 'Module:Coordinates' ) local globe = options.globe or '' if globe == '' and value[ 'globe' ] then local globes = require( 'Module:Wikidata/Globes' ) globe = globes[ value[ 'globe' ] ] or '' end local display = 'inline' if options.display and options.display ~= '' then display = options.display elseif ( options.property:upper() == 'P625' ) then display = 'title' end local format = options.format or '' if format == '' then format = 'dms' if value[ 'precision' ] then local precision = value[ 'precision' ] * 60 if precision >= 60 then format = 'd' elseif precision >= 1 then format = 'dm' end end end g_frame.args = { tostring( value[ 'latitude' ] ), tostring( value[ 'longitude' ] ), globe = globe, type = options.type and options.type or '', scale = options.scale and options.scale or '', display = display, format = format, } return coordModule.coord(g_frame) end end ---Функция для оформления объектов-значений с файлами с Викисклада ---@param value string Raw value. ---@param options table Parameters. ---@return string Formatted string. local function formatCommonsMedia( value, options ) local image = value local caption = '' if options[ 'caption' ] and options[ 'caption' ] ~= '' then caption = options[ 'caption' ] end if caption ~= '' then caption = wrapQualifier( caption, 'P2096', { class = 'media-caption', style = 'display:block' } ) end if not string.find( value, '[%[%]%{%}]' ) and not string.find( value, 'UNIQ%-%-imagemap' ) then -- если в value не содержится викикод или imagemap, то викифицируем имя файла -- ищем слово imagemap в строке, потому что вставляется плейсхолдер: [[phab:T28213]] image = '[[File:' .. value .. '|frameless' if options[ 'border' ] and options[ 'border' ] ~= '' then image = image .. '|border' end local size = options[ 'size' ] if size and size ~= '' then -- TODO: check localized pixel names too if not string.match( size, 'px$' ) then size = size .. 'px' end else size = fileDefaultSize end image = image .. '|' .. size if options[ 'alt' ] and options[ 'alt' ] ~= '' then image = image .. '|alt=' .. options[ 'alt' ] end if caption ~= '' then image = image .. '|' .. caption end image = image .. ']]' if caption ~= '' then image = image .. '<br>' .. caption end else image = image .. caption .. getCategoryByCode( 'media-contains-markup' ) end return image end ---Function for render math formulas ---@param value string Value. ---@param options table Parameters. ---@return string Formatted string. local function formatMath( value, options ) return options.frame:extensionTag{ name = 'math', content = value } end ---Функция для оформления внешних идентификаторов ---@param value string ---@param options table ---@return string local function formatExternalId( value, options ) local formatter = options.formatter local propertyId = options.property:upper() if not formatter or formatter == '' then local isGoodFormat = false local wbStatus, formatRegexStatements = pcall( mw.wikibase.getBestStatements, propertyId, 'P1793' ) if wbStatus and formatRegexStatements then for _, statement in pairs( formatRegexStatements ) do if statement.mainsnak.snaktype == 'value' then local pattern = mw.ustring.gsub( statement.mainsnak.datavalue.value, '\\', '%' ) pattern = mw.ustring.gsub( pattern, '{%d+,?%d*}', '+' ) if ( string.find( pattern, '|' ) or string.find( pattern, '%)%?' ) or mw.ustring.match( value, '^' .. pattern .. '$' ) ~= nil ) then isGoodFormat = true break end end end end if isGoodFormat then local formatterStatements wbStatus, formatterStatements = pcall( mw.wikibase.getBestStatements, propertyId, 'P1630' ) if wbStatus and formatterStatements then for _, statement in pairs( formatterStatements ) do if statement.mainsnak.snaktype == 'value' then formatter = statement.mainsnak.datavalue.value break end end end end end if formatter and formatter ~= '' then local encodedValue = mw.ustring.gsub( value, '%%', '%%%%' ) -- ломается, если подставить внутрь другого mw.ustring.gsub local link = mw.ustring.gsub( mw.ustring.gsub( formatter, '$1', encodedValue ), '.', { [ ' ' ] = '%20', [ '+' ] = '%2b', [ '[' ] = '%5B', [ ']' ] = '%5D' } ) local title = options.title if not title or title == '' then title = '$1' end title = mw.ustring.gsub( mw.ustring.gsub( title, '$1', encodedValue ), '.', { [ '[' ] = '(', [ ']' ] = ')' } ) return '[' .. link .. ' ' .. title .. ']' end return value end ---Функция для оформления числовых значений ---@param value table Объект-значение ---@param options table Таблица параметров ---@return string Оформленный текст local function formatQuantity( value, options ) -- диапазон значений local amount = string.gsub( value.amount, '^%+', '' ) local lang = mw.language.getContentLanguage() local langCode = lang:getCode() local function formatNum( number, sigfig ) local multiplier = '' if options.countByThousands then local powers = options.i18n.thousandPowers local pos = 1 while math.abs( number ) >= 1000 and pos < #powers do number = number / 1000 pos = pos + 1 end multiplier = powers[ pos ] if math.abs( number ) >= 100 then sigfig = sigfig or 0 elseif math.abs( number ) >= 10 then sigfig = sigfig or 1 else sigfig = sigfig or 2 end else sigfig = sigfig or 12 -- округление до 12 знаков после запятой, на 13-м возникает ошибка в точности end local iMultiplier = 10^sigfig number = math.floor( number * iMultiplier + 0.5 ) / iMultiplier return string.gsub( lang:formatNum( number ), '^-', '−' ) .. multiplier end local out = formatNum( tonumber( amount ) ) if value.upperBound then local diff = tonumber( value.upperBound ) - tonumber( amount ) if diff > 0 then -- временная провека, пока у большинства значений не будет убрано ±0 -- Пробуем понять до какого знака округлять local integer, dot, decimals, _ = value.upperBound:match( '^+?-?(%d*)(%.?)(%d*)(.*)' ) local precision if dot == '' then precision = -integer:match( '0*$' ):len() else precision = #decimals end local bound = formatNum( diff, precision ) if string.match( bound, 'E%-(%d+)' ) then -- если в экспоненциальном формате local digits = tonumber( string.match( bound, 'E%-(%d+)' ) ) - 2 bound = formatNum( diff * 10 ^ digits, precision ) bound = string.sub( bound, 0, 2 ) .. string.rep( '0', digits ) .. string.sub( bound, -string.len( bound ) + 2 ) end out = out .. ' ± ' .. bound end end if options.unit and options.unit ~= '' then if options.unit ~= '-' then out = out .. ' ' .. options.unit end elseif value.unit and string.match( value.unit, 'http://www.wikidata.org/entity/' ) then local unitEntityId = string.gsub( value.unit, 'http://www.wikidata.org/entity/', '' ) if unitEntityId ~= 'undefined' then local wbStatus, unitEntity = pcall( mw.wikibase.getEntity, unitEntityId ) if wbStatus == true and unitEntity then if unitEntity.claims.P2370 and unitEntity.claims.P2370[ 1 ].mainsnak.snaktype == 'value' and not value.upperBound and options.siConversion == true then local conversionToSiUnit = string.gsub( unitEntity.claims.P2370[ 1 ].mainsnak.datavalue.value.amount, '^%+', '' ) if math.floor( math.log10( conversionToSiUnit ) ) ~= math.log10( conversionToSiUnit ) then -- Если не степени десятки (переводить сантиметры в метры не надо!) local outValue = tonumber( amount ) * conversionToSiUnit if outValue > 0 then -- Пробуем понять до какого знака округлять local integer, dot, decimals, _ = amount:match( '^(%d*)(%.?)(%d*)(.*)' ) local precision if dot == '' then precision = -integer:match( '0*$' ):len() else precision = #decimals end local adjust = math.log10( math.abs( conversionToSiUnit ) ) + math.log10( 2 ) local minPrecision = 1 - math.floor( math.log10( outValue ) + 2e-14 ) out = formatNum( outValue, math.max( math.floor( precision + adjust ), minPrecision ) ) else out = formatNum( outValue, 0 ) end unitEntityId = string.gsub( unitEntity.claims.P2370[ 1 ].mainsnak.datavalue.value.unit, 'http://www.wikidata.org/entity/', '' ) wbStatus, unitEntity = pcall( mw.wikibase.getEntity, unitEntityId ) end end local label = getLabelWithLang( context, options, unitEntity.id, nil, { "P5061", "P558", "P558" }, { 'P5061[language:' .. langCode .. ']', 'P558[P282:' .. writingSystemElementId .. ', P407:' .. langElementId .. ']', 'P558[!P282][!P407]' } ) out = out .. ' ' .. label end end end return out end ---Функция для оформления URL ---@param context table ---@param options table ---@param value string local function formatUrlValue( context, options, value ) if not options.length or options.length == '' then options.length = 25 end local moduleUrl = require( 'Module:URL' ) return moduleUrl.formatUrlSingle( context, options, value ) end local DATATYPE_CACHE = {} ---Get property datatype by ID. ---@param propertyId string Property ID, e.g. 'P123'. ---@return string Property datatype, e.g. 'commonsMedia', 'time' or 'url'. local function getPropertyDatatype( propertyId ) if not propertyId or not string.match( propertyId, '^P%d+$' ) then return nil end local cached = DATATYPE_CACHE[ propertyId ] if cached ~= nil then return cached end local wbStatus, propertyEntity = pcall( mw.wikibase.getEntity, propertyId ) if wbStatus ~= true or not propertyEntity then return nil end mw.log("Loaded datatype " .. propertyEntity.datatype .. " of " .. propertyId .. ' from wikidata, consider passing datatype argument to formatProperty call or to Wikidata/config' ) DATATYPE_CACHE[ propertyId ] = propertyEntity.datatype return propertyEntity.datatype end ---@param datavalue table ---@return function local function getPlainValueFunction( datavalue, _ ) if datavalue.type == 'wikibase-entityid' then return function( _, _, value ) return getEntityIdFromValue( value ) end elseif datavalue.type == 'string' then return function( _, _, value ) return value end elseif datavalue.type == 'monolingualtext' then return function( _, _, value ) return value.text end elseif datavalue.type == 'globecoordinate' then return function( _, _, value ) return value.latitude .. ',' .. value.longitude end elseif datavalue.type == 'quantity' then return function( _, _, value ) return value.amount end elseif datavalue.type == 'time' then return function( _, _, value ) return value.time end end throwError( 'unknown-datavalue-type' ) end ---@param datavalue table ---@param datatype string ---@return function local function getDefaultValueFunction( datavalue, datatype ) -- вызов обработчиков по умолчанию для известных типов значений if datavalue.type == 'wikibase-entityid' then -- Entity ID return function( context, options, value ) return formatEntityId( context, options, getEntityIdFromValue( value ) ) end elseif datavalue.type == 'string' then -- String if datatype and datatype == 'commonsMedia' then -- Media return function( _, options, value ) return formatCommonsMedia( value, options ) end elseif datatype and datatype == 'external-id' then -- External ID return function( _, options, value ) return formatExternalId( value, options ) end elseif datatype and datatype == 'math' then -- Math formula return function( _, options, value ) return formatMath( value, options ) end elseif datatype and datatype == 'url' then -- URL return formatUrlValue end return function( _, _, value ) return value end elseif datavalue.type == 'monolingualtext' then -- моноязычный текст (строка с указанием языка) return function( _, options, value ) if options.monolingualLangTemplate == 'lang' then if value.language == CONTENT_LANGUAGE_CODE then return value.text end return options.frame:expandTemplate{ title = 'lang-' .. value.language, args = { value.text } } elseif options.monolingualLangTemplate == 'ref' then return '<span class="lang" lang="' .. value.language .. '">' .. value.text .. '</span>' .. options.frame:expandTemplate{ title = 'ref-' .. value.language } else return '<span class="lang" lang="' .. value.language .. '">' .. value.text .. '</span>' end end elseif datavalue.type == 'globecoordinate' then -- географические координаты return function( _, options, value ) return formatGlobeCoordinate( value, options ) end elseif datavalue.type == 'quantity' then return function( _, options, value ) return formatQuantity( value, options ) end elseif datavalue.type == 'time' then return function( context, options, value ) local moduleDate = require( 'Module:Wikidata/date' ) return moduleDate.formatDate( context, options, value ) end end -- во всех стальных случаях возвращаем ошибку throwError( 'unknown-datavalue-type' ) end ---Функция для оформления значений (value) ---Подробнее о значениях см. d:Wikidata:Glossary/ru ---@param context table ---@param options table ---@param datavalue table ---@param datatype string ---@return string Оформленный текст function formatDatavalue( context, options, datavalue, datatype ) if not context then error( 'context not specified' ); end if not options then error( 'options not specified' ); end if not datavalue then error( 'datavalue not specified' ); end if not datavalue.value then error( 'datavalue.value is missing' ); end -- проверка на указание специализированных обработчиков в параметрах, -- переданных при вызове if options.plain then context.formatValueDefault = getPlainValueFunction( datavalue, datatype ) else context.formatValueDefault = getDefaultValueFunction( datavalue, datatype ) end local functionToCall = getUserFunction( options, 'value', context.formatValueDefault ) return functionToCall( context, options, datavalue.value ) end local DEFAULT_BOUNDARIES = { os.time() * 1000, os.time() * 1000} ---Функция для оформления идентификатора сущности ---@param context table ---@param options table ---@param entityId string ---@return string Оформленный текст function formatEntityId( context, options, entityId ) -- получение локализованного названия local boundaries if options.qualifiers then boundaries = p.getTimeBoundariesFromQualifiers( context.frame, context, { qualifiers = options.qualifiers } ) end if not boundaries then boundaries = DEFAULT_BOUNDARIES end local label, labelLanguageCode = getLabelWithLang( context, options, entityId, boundaries ) -- определение соответствующей показываемому элементу категории local category = context.extractCategory( options, { id = entityId } ) -- получение ссылки по идентификатору local link = mw.wikibase.sitelink( entityId ) if link then -- ссылка на категорию, а не добавление страницы в неё if mw.ustring.match( link, '^' .. mw.site.namespaces[ 14 ].name .. ':' ) then link = ':' .. link end if label and not options.rawArticle then if labelLanguageCode ~= CONTENT_LANGUAGE_CODE then label = '<span lang="' .. label .. '">' .. label .. '</span>' end local a = '[[' .. link .. '|' .. label .. ']]' if CONTENT_LANGUAGE_CODE ~= labelLanguageCode and 'mul' ~= labelLanguageCode then a = a .. getCategoryByCode( 'links-to-entities-with-missing-local-language-label' ) end return a .. category else return '[[' .. link .. ']]' .. category end end if label then -- TODO: возможно, лучше просто mw.wikibase.getLabel(entityId) -- красная ссылка -- TODO: разобраться, почему не всегда есть options.frame local moduleRedLink = require( 'Module:Wikidata/redLink' ) local title = mw.title.new( label ) if title and not title.exists and options.frame then local rawLabel = mw.wikibase.getLabel(entityId) or label -- без |text= и boundaries; or label - костыль local redLink = moduleRedLink.formatRedLinkWithInfobox(rawLabel, label, entityId) if CONTENT_LANGUAGE_CODE ~= labelLanguageCode and 'mul' ~= labelLanguageCode then redLink = '<span lang="' .. labelLanguageCode .. '">' .. redLink .. '</span>' .. getCategoryByCode( 'links-to-entities-with-missing-local-language-label' ) end return redLink .. category end -- TODO: перенести до проверки на существование статьи local addWdLink = false if ( not options.format or options.format ~= 'text' ) and entityId ~= 'Q6581072' and entityId ~= 'Q6581097' -- TODO: переписать на format=text then addWdLink = true end -- одноимённая статья уже существует - выводится текст и ссылка на ВД return moduleRedLink.formatText(label, entityId, addWdLink) .. category end -- сообщение об отсутвии локализованного названия -- not good, but better than nothing return '[[:d:' .. entityId .. '|' .. entityId .. ']]<span style="border-bottom: 1px dotted; cursor: help; white-space: nowrap" title="В Викиданных нет русской подписи к элементу. Вы можете помочь, указав русский вариант подписи.">?</span>' .. getCategoryByCode( 'links-to-entities-with-missing-label' ) .. category end ---Функция для оформления утверждений (statement) ---Подробнее о утверждениях см. d:Wikidata:Glossary/ru ---@deprecated Use p.formatProperty() instead ---@param frame table ---@return string Строка оформленного текста, предназначенная для отображения в статье function p.formatStatements( frame ) return p.formatProperty( frame ) end ---Получение параметров, которые обычно используются для вывода свойства. ---@param propertyId string ---@param datatype string ---@param params table function getPropertyParams( propertyId, datatype, params ) local config = getConfig() -- Различные уровни настройки параметров, по убыванию приоритета local propertyParams = {} -- 1. Параметры, указанные явно при вызове if params then for key, value in pairs( params ) do if value ~= '' then propertyParams[ key ] = value end end end if toBoolean( propertyParams.plain, false ) then propertyParams.separator = propertyParams.separator or ', ' propertyParams.conjunction = propertyParams.conjunction or ', ' else -- 2. Настройки конкретного параметра if config.properties and config.properties[ propertyId ] then for key, value in pairs( config.properties[ propertyId ] ) do if propertyParams[ key ] == nil then propertyParams[ key ] = value end end end -- 3. Указанный пресет настроек if propertyParams.preset and config.presets and config.presets[ propertyParams.preset ] then for key, value in pairs( config.presets[ propertyParams.preset ] ) do if propertyParams[ key ] == nil then propertyParams[ key ] = value end end end datatype = datatype or params.datatype or propertyParams.datatype or getPropertyDatatype( propertyId ) if propertyParams.datatype == nil then propertyParams.datatype = datatype end -- 4. Настройки для типа данных if datatype and config.datatypes and config.datatypes[ datatype ] then for key, value in pairs( config.datatypes[ datatype ] ) do if propertyParams[ key ] == nil then propertyParams[ key ] = value end end end -- 5. Общие настройки для всех свойств if config.global then for key, value in pairs( config.global ) do if propertyParams[ key ] == nil then propertyParams[ key ] = value end end end end return propertyParams end ---Функция для оформления утверждений (statement) ---Подробнее о утверждениях см. d:Wikidata:Glossary/ru ---@param frame table ---@return string Строка оформленного текста, предназначенная для отображения в статье function p.formatProperty( frame ) local args = copyTo( frame.args, {} ) -- проверка на отсутствие обязательного параметра property if not args.property then throwError( 'property-param-not-provided' ) end local override local propertyId = mw.language.getContentLanguage():ucfirst( string.gsub( args.property, '([^Pp0-9].*)$', function(w) if string.sub( w, 1, 1 ) == '~' then override = w end return '' end ) ) if override then args[ override:match( '[,~]([^=]*)=' ) ] = override:match( '=(.*)' ) args.property = propertyId end -- проброс всех параметров из шаблона {wikidata} и параметра from откуда угодно local p_frame = frame while p_frame do if p_frame:getTitle() == mw.site.namespaces[ 10 ].name .. ':Wikidata' then copyTo( p_frame.args, args, true ) end if p_frame.args and p_frame.args.from and p_frame.args.from ~= '' then args.entityId = p_frame.args.from else args.entityId = mw.wikibase.getEntityIdForCurrentPage() end p_frame = p_frame:getParent() end args = getPropertyParams( propertyId, nil, args ) local datatype = args.datatype -- перевод итоговых значений флагов в true/false и добавление значений -- по умолчанию только в том случае, если они нигде не были указаны ранее args.plain = toBoolean( args.plain, false ) args.nocat = not args.plain and toBoolean( args.nocat, false ) args.references = not args.plain and toBoolean( args.references, true ) -- если значение передано в параметрах вызова то выводим только его if args.value and args.value ~= '' then -- специальное значение для скрытия Викиданных if args.value == '-' then return '' end local value = args.value -- опция, запрещающая оформление значения, поэтому никак не трогаем if args.plain then return value end local context = initContext( args ) -- обработчики по типу значения local wrapperExtraArgs = {} if args[ 'value-module' ] and args[ 'value-function' ] and not string.find( value, '[%[%]%{%}]' ) then local func = getUserFunction( args, 'value' ) value = func( context, args, value ) elseif datatype == 'commonsMedia' then value = formatCommonsMedia( value, args ) elseif datatype == 'external-id' and not string.find( value, '[%[%]%{%}]' ) then wrapperExtraArgs[ 'data-wikidata-external-id' ] = mw.text.killMarkers( value ) value = formatExternalId( value, args ) --elseif datatype == 'math' then -- args.frame = frame -- костыль: в formatMath нужно frame:extensionTag -- value = formatMath( value, args ) elseif datatype == 'url' then value = formatUrlValue( context, args, value ) end -- оборачиваем в тег для JS-функций if string.match( propertyId, '^P%d+$' ) then value = mw.text.trim( value ) -- временная штрафная категория для исправления табличных вставок local allowTables = getPropertyParams( propertyId, nil, {} ).allowTables if not allowTables and string.match( value, '<t[dhr][ >]' ) -- and not string.match( value, '<table[ >]' ) -- and not string.match( value, '^%{%|' ) then value = value .. getCategoryByCode( 'value-contains-table', propertyId ) else value = wrapStatement( value, propertyId, nil, wrapperExtraArgs ) end end return value end -- ability to disable loading Wikidata if args.entityId == '-' then return '' end g_frame = frame -- после проверки всех аргументов -- вызов функции оформления для свойства (набора утверждений) return formatProperty( args ) end ---Функция проверки на присутствие источника в списке нерекомендованных. ---@param snaks table ---@return boolean local function isReferenceDeprecated( snaks ) if not snaks then return false end if snaks.P248 and snaks.P248[ 1 ] and snaks.P248[ 1 ].datavalue and snaks.P248[ 1 ].datavalue.value.id then local entityId = snaks.P248[ 1 ].datavalue.value.id if getConfig( 'deprecatedSources', entityId ) then return true end elseif snaks.P1433 and snaks.P1433[ 1 ] and snaks.P1433[ 1 ].datavalue and snaks.P1433[ 1 ].datavalue.value.id then local entityId = snaks.P1433[ 1 ].datavalue.value.id if getConfig( 'deprecatedSources', entityId ) then return true end end return false end ---Функция оформления ссылок на источники (reference) ---Подробнее о ссылках на источники см. d:Wikidata:Glossary/ru --- ---Экспортируется в качестве зарезервированной точки для вызова из функций-расширения вида claim-module/claim-function через context ---Вызов из других модулей напрямую осуществляться не должен (используйте frame:expandTemplate вместе с одним из специлизированных шаблонов вывода значения свойства). ---@param context table ---@param options table ---@param statement table ---@return string Оформленные примечания для отображения в статье function formatRefs( context, options, statement ) if not context then error( 'context not specified' ); end if not options then error( 'options not specified' ); end if not options.entityId then error( 'options.entityId missing' ); end if not statement then error( 'statement not specified' ); end if not outputReferences then return '' end ---@type string[] local references = {} if statement.references then local hasNotDeprecated = false local displayCount = 0 for _, reference in pairs( statement.references ) do if not isReferenceDeprecated( reference.snaks ) then hasNotDeprecated = true end end for _, reference in pairs( statement.references ) do local display = true if hasNotDeprecated then if isReferenceDeprecated( reference.snaks ) then display = false end end if displayCount >= 2 then if options.entityId and options.property then local propertyId = mw.ustring.match( options.property, '^[Pp][0-9]+' ) -- TODO: обрабатывать не тут, а раньше local moreReferences = '<sup>[[d:' .. options.entityId .. '#' .. string.upper( propertyId ) .. '|[…]]]</sup>' table.insert( references, moreReferences ) end break end if display == true then ---@type string local refText = moduleSources.renderReference( g_frame, options.entityId, reference ) if refText and refText ~= '' then table.insert( references, refText ) displayCount = displayCount + 1 end end end end return table.concat( references ) end return p 4558f762f30c6ebfb9f5333dbd7ebda83c6873f2 Модуль:Wikidata/media 828 54 105 2024-10-26T15:20:21Z wikipedia:ru>Stjn 0 [[ВП:×|отмена]]: сломало отображение в множестве статей Scribunto text/plain local p = {} -- Константы local contentLanguageCode = mw.getContentLanguage():getCode(); function p.formatCommonsCategory( context, options, value ) local link = 'commons:Category:' .. value local title = value .. ' на Викискладе' if ( options['text'] and options['text'] ~= '' ) then title = options['text'] end commons = '[[' .. link .. '|' .. title .. ']]' --Commons icon if ( not options['icon'] or options['icon'] ~= '-' ) then local icon_size = '15px' if ( options['icon_size'] and options['icon_size'] ~= '' ) then icon_size = options['icon_size'] end commons = '[[File:Commons-logo.svg|' .. icon_size .. '|link=' .. link .. '|alt=Логотип Викисклада]] ' .. commons end --Text before and after link if ( options['text_before'] and options['text_before'] ~= '' ) then if ( options['text_before'] ~= '-' ) then commons = options['text_before'] .. ' ' .. commons end end if ( options['text_after'] and options['text_after'] ~= '' ) then if ( options['text_after'] ~= '-' ) then commons = commons .. ' ' .. options['text_after'] end end return commons end --[[ Временный хак, нужно добавить config, getConfig и getCategoryByCode в options, чтобы они были доступны в любом месте кода. ]] local config; local function getCategoryByCode( code, sortkey ) if config == nil then config = require( 'Module:Wikidata/config' ); end; local value = config[ 'categories' ][ code ]; if not value or value == '' then return ''; end return '[[Category:' .. value .. ']]'; end local function getCaption( context, options ) local caption = '' if options.qualifiers and options.qualifiers.P2096 then for i, qualifier in pairs( options.qualifiers.P2096 ) do if ( qualifier and qualifier.datavalue and qualifier.datavalue.type == 'monolingualtext' and qualifier.datavalue.value and qualifier.datavalue.value.language == contentLanguageCode ) then caption = qualifier.datavalue.value.text break end end end if options['appendTimestamp'] and options.qualifiers and options.qualifiers.P585 and options.qualifiers.P585[1] then local moment = context.formatValueDefault( context, options, options.qualifiers.P585[1].datavalue ) if not caption or caption == '' then caption = moment else caption = caption .. ', ' .. moment end end local localValue = ''; if options[ 'value' ] and options[ 'value' ] ~= '' then localValue = options[ 'value' ]; end local localCaption = ''; if options[ 'caption' ] and options[ 'caption' ] ~= '' then localCaption = options[ 'caption' ]; end if localValue ~= '' then caption = localCaption; end local formattedCaption = '' if caption ~= '' then formattedCaption = context.wrapQualifier( caption, 'P2096', { class = 'media-caption', style = 'display:block' } ); end if localValue == '' and localCaption ~= '' then formattedCaption = formattedCaption .. getCategoryByCode( 'media-contains-local-caption' ) if options.frame:preprocess('{{REVISIONID}}') == '' then formattedCaption = formattedCaption .. '<span class="error" style="font-size:94%;">Локальная подпись не используется, потому что изображение берётся из Викиданных, см. [[Википедия:Шаблоны-карточки#Описание изображения в Викиданных|здесь]]</span>' end end return caption, formattedCaption end function p.formatCommonsMediaValue( context, options, value ) local image = value; local caption, formattedCaption = getCaption( context, options ) if not string.find( value, '[%[%]%{%}]' ) and not string.find( value, 'UNIQ%-%-imagemap' ) then -- если в value не содержится викикод или imagemap, то викифицируем имя файла -- ищем слово imagemap в строке, потому что вставляется плейсхолдер: [[PHAB:T28213]] image = '[[File:' .. value .. '|frameless'; if options[ 'border' ] and options[ 'border' ] ~= '' then image = image .. '|border'; end local size = options[ 'size' ]; if size and size ~= '' then if not string.match( size, 'px$' ) and not string.match( size, 'пкс$' ) -- TODO: использовать перевод для языка вики then size = size .. 'px' end -- временно if string.match( size, 'pxpx' ) then image = '[[Категория:Википедия:Изображение с pxpx в размере]]' .. image end else size = fileDefaultSize; end image = image .. '|' .. size; if options[ 'alt' ] and options[ 'alt' ] ~= '' then image = image .. '|alt=' .. options[ 'alt' ]; end if caption ~= '' then image = image .. '|' .. caption end image = image .. ']]'; if formattedCaption ~= '' then image = image .. '<br>' .. formattedCaption; end else image = image .. formattedCaption .. getCategoryByCode( 'media-contains-markup' ); end if options.entity and options.fixdouble then local page = mw.title.getCurrentTitle() local txt = page:getContent() if txt and txt:match(':' .. value) and mw.title.getCurrentTitle():inNamespace(0) then if options.frame:preprocess('{{REVISIONID}}') == '' then image = image .. '<span class="error">Это изображение встречается ниже по тексту статьи; пожалуйста, уберите одну из копий (не потеряв при этом подпись)</span>' end image = image .. getCategoryByCode( 'media-contains-local-double' ) end end return image end return p ec384e72491465f4103cce95a8f9467df428a432 Модуль:String 828 30 57 2024-11-18T02:41:06Z wikipedia:ru>Stjn 0 аналогично английскому разделу — mw.ustring.gsub тут не нужен Scribunto text/plain --[[ This module is intended to provide access to basic string functions. Most of the functions provided here can be invoked with named parameters, unnamed parameters, or a mixture. If named parameters are used, Mediawiki will automatically remove any leading or trailing whitespace from the parameter. Depending on the intended use, it may be advantageous to either preserve or remove such whitespace. Global options ignore_errors: If set to 'true' or 1, any error condition will result in an empty string being returned rather than an error message. error_category: If an error occurs, specifies the name of a category to include with the error message. The default category is [Category:Errors reported by Module String]. no_category: If set to 'true' or 1, no category will be added if an error is generated. Unit tests for this module are available at Module:String/tests. ]] local str = {} --[[ subcount This function returns the count of substring in source string. Usage: {{#invoke:String|subcount|source_string|substring|plain_flag}} OR {{#invoke:String|subcount|s=source_string|pattern=substring|plain=plain_flag}} Parameters s: The string to search pattern: The pattern or string to find within the string plain: A flag indicating that the substring should be understood as plain text. Defaults to true. If invoked using named parameters, Mediawiki will automatically remove any leading or trailing whitespace from the target string. ]] function str.subcount( frame ) local new_args = str._getParameters( frame.args, {'s', 'pattern', 'plain'} ); local s = new_args['s'] or ''; local plain_flag = str._getBoolean( new_args['plain'] or true ); local pattern = new_args['pattern'] or ''; if s == '' or pattern == '' then return 0; end if plain_flag then pattern = str._escapePattern( pattern ); end local _, count = mw.ustring.gsub(s, pattern, "") return count; end --[[ len This function returns the length of the target string. Usage: {{#invoke:String|len|target_string|}} OR {{#invoke:String|len|s=target_string}} Parameters s: The string whose length to report If invoked using named parameters, Mediawiki will automatically remove any leading or trailing whitespace from the target string. ]] function str.len( frame ) local new_args = str._getParameters( frame.args, {'s'} ); local s = new_args['s'] or ''; return mw.ustring.len( s ) end --[[ sub This function returns a substring of the target string at specified indices. Usage: {{#invoke:String|sub|target_string|start_index|end_index}} OR {{#invoke:String|sub|s=target_string|i=start_index|j=end_index}} Parameters s: The string to return a subset of i: The fist index of the substring to return, defaults to 1. j: The last index of the string to return, defaults to the last character. The first character of the string is assigned an index of 1. If either i or j is a negative value, it is interpreted the same as selecting a character by counting from the end of the string. Hence, a value of -1 is the same as selecting the last character of the string. If the requested indices are out of range for the given string, an error is reported. ]] function str.sub( frame ) local new_args = str._getParameters( frame.args, { 's', 'i', 'j' } ); local s = new_args['s'] or ''; local i = tonumber( new_args['i'] ) or 1; local j = tonumber( new_args['j'] ) or -1; local len = mw.ustring.len( s ); -- Convert negatives for range checking if i < 0 then i = len + i + 1; end if j < 0 then j = len + j + 1; end if i > len or j > len or i < 1 or j < 1 then return str._error( 'Значение индекса подстроки выходит за допустимые границы' ); end if j < i then return str._error( 'Неверный порядок индексов подстроки' ); end return mw.ustring.sub( s, i, j ) end --[[ This function implements that features of {{str sub old}} and is kept in order to maintain these older templates. ]] function str.sublength( frame ) local i = tonumber( frame.args.i ) or 0 local len = tonumber( frame.args.len ) return mw.ustring.sub( frame.args.s, i + 1, len and ( i + len ) ) end --[[ match This function returns a substring from the source string that matches a specified pattern. Usage: {{#invoke:String|match|source_string|pattern_string|start_index|match_number|plain_flag|nomatch_output}} OR {{#invoke:String|pos|s=source_string|pattern=pattern_string|start=start_index |match=match_number|plain=plain_flag|nomatch=nomatch_output}} Parameters s: The string to search pattern: The pattern or string to find within the string start: The index within the source string to start the search. The first character of the string has index 1. Defaults to 1. match: In some cases it may be possible to make multiple matches on a single string. This specifies which match to return, where the first match is match= 1. If a negative number is specified then a match is returned counting from the last match. Hence match = -1 is the same as requesting the last match. Defaults to 1. plain: A flag indicating that the pattern should be understood as plain text. Defaults to false. nomatch: If no match is found, output the "nomatch" value rather than an error. If invoked using named parameters, Mediawiki will automatically remove any leading or trailing whitespace from each string. In some circumstances this is desirable, in other cases one may want to preserve the whitespace. If the match_number or start_index are out of range for the string being queried, then this function generates an error. An error is also generated if no match is found. If one adds the parameter ignore_errors=true, then the error will be suppressed and an empty string will be returned on any failure. For information on constructing Lua patterns, a form of [regular expression], see: * http://www.lua.org/manual/5.1/manual.html#5.4.1 * http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Patterns * http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Ustring_patterns ]] function str.match( frame ) local new_args = str._getParameters( frame.args, {'s', 'pattern', 'start', 'match', 'plain', 'nomatch'} ); local s = new_args['s'] or ''; local start = tonumber( new_args['start'] ) or 1; local plain_flag = str._getBoolean( new_args['plain'] or false ); local pattern = new_args['pattern'] or ''; local match_index = math.floor( tonumber(new_args['match']) or 1 ); local nomatch = new_args['nomatch']; if s == '' then return str._error( 'Пустая строка поиска' ); end if pattern == '' then return str._error( 'Пустой шаблон поиска' ); end if math.abs(start) < 1 or math.abs(start) > mw.ustring.len( s ) then return str._error( 'Индекс начала поиска выходит за допустимые границы' ); end if match_index == 0 then return str._error( 'Индекс совпадения выходит за допустимые границы' ); end if plain_flag then pattern = str._escapePattern( pattern ); end local result if match_index == 1 then -- Find first match is simple case result = mw.ustring.match( s, pattern, start ) else if start > 1 then s = mw.ustring.sub( s, start ); end local iterator = mw.ustring.gmatch(s, pattern); if match_index > 0 then -- Forward search for w in iterator do match_index = match_index - 1; if match_index == 0 then result = w; break; end end else -- Reverse search local result_table = {}; local count = 1; for w in iterator do result_table[count] = w; count = count + 1; end result = result_table[ count + match_index ]; end end if result == nil then if nomatch == nil then return str._error( 'Совпадение не найдено' ); else return nomatch; end else return result; end end --[[ pos This function returns a single character from the target string at position pos. Usage: {{#invoke:String|pos|target_string|index_value}} OR {{#invoke:String|pos|target=target_string|pos=index_value}} Parameters target: The string to search pos: The index for the character to return If invoked using named parameters, Mediawiki will automatically remove any leading or trailing whitespace from the target string. In some circumstances this is desirable, in other cases one may want to preserve the whitespace. The first character has an index value of 1. If one requests a negative value, this function will select a character by counting backwards from the end of the string. In other words pos = -1 is the same as asking for the last character. A requested value of zero, or a value greater than the length of the string returns an error. ]] function str.pos( frame ) local new_args = str._getParameters( frame.args, {'target', 'pos'} ); local target_str = new_args['target'] or ''; local pos = tonumber( new_args['pos'] ) or 0; if pos == 0 or math.abs(pos) > mw.ustring.len( target_str ) then return str._error( 'Значение индекса строки выходит за допустимые границы' ); end return mw.ustring.sub( target_str, pos, pos ); end --[[ str_find This function duplicates the behavior of {{str_find}}, including all of its quirks. This is provided in order to support existing templates, but is NOT RECOMMENDED for new code and templates. New code is recommended to use the "find" function instead. Returns the first index in "source" that is a match to "target". Indexing is 1-based, and the function returns -1 if the "target" string is not present in "source". Important Note: If the "target" string is empty / missing, this function returns a value of "1", which is generally unexpected behavior, and must be accounted for separatetly. ]] function str.str_find( frame ) local new_args = str._getParameters( frame.args, {'source', 'target'} ); local source_str = new_args['source'] or ''; local target_str = new_args['target'] or ''; if target_str == '' then return 1; end local start = mw.ustring.find( source_str, target_str, 1, true ) if start == nil then start = -1 end return start end --[[ find This function allows one to search for a target string or pattern within another string. Usage: {{#invoke:String|find|source_str|target_string|start_index|plain_flag}} OR {{#invoke:String|find|source=source_str|target=target_str|start=start_index|plain=plain_flag}} Parameters source: The string to search target: The string or pattern to find within source start: The index within the source string to start the search, defaults to 1 plain: Boolean flag indicating that target should be understood as plain text and not as a Lua style regular expression, defaults to true If invoked using named parameters, Mediawiki will automatically remove any leading or trailing whitespace from the parameter. In some circumstances this is desirable, in other cases one may want to preserve the whitespace. This function returns the first index >= "start" where "target" can be found within "source". Indices are 1-based. If "target" is not found, then this function returns 0. If either "source" or "target" are missing / empty, this function also returns 0. This function should be safe for UTF-8 strings. ]] function str.find( frame ) local new_args = str._getParameters( frame.args, {'source', 'target', 'start', 'plain' } ); local source_str = new_args['source'] or ''; local pattern = new_args['target'] or ''; local start_pos = tonumber(new_args['start']) or 1; local plain = new_args['plain'] or true; if source_str == '' or pattern == '' then return 0; end plain = str._getBoolean( plain ); local start = mw.ustring.find( source_str, pattern, start_pos, plain ) if start == nil then start = 0 end return start end --[[ replace This function allows one to replace a target string or pattern within another string. Usage: {{#invoke:String|replace|source_str|pattern_string|replace_string|replacement_count|plain_flag}} OR {{#invoke:String|replace|source=source_string|pattern=pattern_string|replace=replace_string| count=replacement_count|plain=plain_flag}} Parameters source: The string to search pattern: The string or pattern to find within source replace: The replacement text count: The number of occurences to replace, defaults to all. plain: Boolean flag indicating that pattern should be understood as plain text and not as a Lua style regular expression, defaults to true ]] function str.replace( frame ) local new_args = str._getParameters( frame.args, {'source', 'pattern', 'replace', 'count', 'plain' } ); local source_str = new_args['source'] or ''; local pattern = new_args['pattern'] or ''; local replace = new_args['replace'] or ''; local count = tonumber( new_args['count'] ); local plain = new_args['plain'] or true; if source_str == '' or pattern == '' then return source_str; end plain = str._getBoolean( plain ); if plain then pattern = str._escapePattern( pattern ); replace = string.gsub( replace, "%%", "%%%%" ) --Only need to escape replacement sequences. end local result; if count ~= nil then result = mw.ustring.gsub( source_str, pattern, replace, count ); else result = mw.ustring.gsub( source_str, pattern, replace ); end return result; end --[[ This function adds support for escaping parts of the patterns when using [plain=false]. ]] function str.escape( frame ) local new_args = str._getParameters( frame.args, {'pattern' } ); local pattern = new_args['pattern'] or ''; local result = ''; result = str._escapePattern( pattern ); return result; end --[[ Internal compare string function ]] function str._strcmp(a , b) local s1c = mw.ustring.gcodepoint( a ); local s2c = mw.ustring.gcodepoint( b ); while true do local c1 = s1c(); local c2 = s2c(); if c1 == nil then if c2 == nil then return 0 else return -1 end else if c2 ~= nil then if c1 ~= c2 then return c1 < c2 and -1 or 1 end else return 1 end end end return 0 end --[[ compare This function compare two UTF-8 strings Usage: {{#invoke:String|compare|str1|str2}} Returns: 0 - if strings are equal 1 - if st1 > str2 -1 - if str1 < str2 ]] function str.compare(frame) local str1 = frame.args[1] or ''; local str2 = frame.args[2] or ''; return str._strcmp(str1 , str2) end --[[ simple function to pipe string.rep to templates. ]] function str.rep( frame ) local repetitions = tonumber( frame.args[2] ) if not repetitions then return str._error( 'функция rep ожидает число во втором параметре, а получено "' .. ( frame.args[2] or '' ) .. '"' ) end return string.rep( frame.args[1] or '', repetitions ) end --[[ Helper function that populates the argument list given that user may need to use a mix of named and unnamed parameters. This is relevant because named parameters are not identical to unnamed parameters due to string trimming, and when dealing with strings we sometimes want to either preserve or remove that whitespace depending on the application. ]] function str._getParameters( frame_args, arg_list ) local new_args = {}; local index = 1; local value; for i,arg in ipairs( arg_list ) do value = frame_args[arg] if value == nil then value = frame_args[index]; index = index + 1; end new_args[arg] = value; end return new_args; end --[[ Helper function to handle error messages. ]] function str._error( error_str ) local frame = mw.getCurrentFrame(); local error_category = frame.args.error_category or 'Страницы с ошибками модуля String'; local ignore_errors = frame.args.ignore_errors or false; local no_category = frame.args.no_category or false; if str._getBoolean(ignore_errors) then return ''; end local error_str = '<strong class="error">Ошибка модуля String: ' .. error_str .. '</strong>'; if error_category ~= '' and not str._getBoolean( no_category ) then error_str = '[[Категория:' .. error_category .. ']]' .. error_str; end return error_str; end --[[ Helper Function to interpret boolean strings ]] function str._getBoolean( boolean_str ) local boolean_value; if type( boolean_str ) == 'string' then boolean_str = boolean_str:lower(); if boolean_str == 'false' or boolean_str == 'no' or boolean_str == '0' or boolean_str == '' then boolean_value = false; else boolean_value = true; end elseif type( boolean_str ) == 'boolean' then boolean_value = boolean_str; else error( 'Логическое значение не найдено' ); end return boolean_value end --[[ Helper function that escapes all pattern characters so that they will be treated as plain text. ]] function str._escapePattern( pattern_str ) return ( string.gsub( pattern_str, "[%(%)%.%%%+%-%*%?%[%^%$%]]", "%%%0" ) ) end return str 2c7347f1dafbbc0efc196c148a1f81e7b82420dc 58 57 2025-01-25T21:00:16Z Vallenland 2 1 версия импортирована Scribunto text/plain --[[ This module is intended to provide access to basic string functions. Most of the functions provided here can be invoked with named parameters, unnamed parameters, or a mixture. If named parameters are used, Mediawiki will automatically remove any leading or trailing whitespace from the parameter. Depending on the intended use, it may be advantageous to either preserve or remove such whitespace. Global options ignore_errors: If set to 'true' or 1, any error condition will result in an empty string being returned rather than an error message. error_category: If an error occurs, specifies the name of a category to include with the error message. The default category is [Category:Errors reported by Module String]. no_category: If set to 'true' or 1, no category will be added if an error is generated. Unit tests for this module are available at Module:String/tests. ]] local str = {} --[[ subcount This function returns the count of substring in source string. Usage: {{#invoke:String|subcount|source_string|substring|plain_flag}} OR {{#invoke:String|subcount|s=source_string|pattern=substring|plain=plain_flag}} Parameters s: The string to search pattern: The pattern or string to find within the string plain: A flag indicating that the substring should be understood as plain text. Defaults to true. If invoked using named parameters, Mediawiki will automatically remove any leading or trailing whitespace from the target string. ]] function str.subcount( frame ) local new_args = str._getParameters( frame.args, {'s', 'pattern', 'plain'} ); local s = new_args['s'] or ''; local plain_flag = str._getBoolean( new_args['plain'] or true ); local pattern = new_args['pattern'] or ''; if s == '' or pattern == '' then return 0; end if plain_flag then pattern = str._escapePattern( pattern ); end local _, count = mw.ustring.gsub(s, pattern, "") return count; end --[[ len This function returns the length of the target string. Usage: {{#invoke:String|len|target_string|}} OR {{#invoke:String|len|s=target_string}} Parameters s: The string whose length to report If invoked using named parameters, Mediawiki will automatically remove any leading or trailing whitespace from the target string. ]] function str.len( frame ) local new_args = str._getParameters( frame.args, {'s'} ); local s = new_args['s'] or ''; return mw.ustring.len( s ) end --[[ sub This function returns a substring of the target string at specified indices. Usage: {{#invoke:String|sub|target_string|start_index|end_index}} OR {{#invoke:String|sub|s=target_string|i=start_index|j=end_index}} Parameters s: The string to return a subset of i: The fist index of the substring to return, defaults to 1. j: The last index of the string to return, defaults to the last character. The first character of the string is assigned an index of 1. If either i or j is a negative value, it is interpreted the same as selecting a character by counting from the end of the string. Hence, a value of -1 is the same as selecting the last character of the string. If the requested indices are out of range for the given string, an error is reported. ]] function str.sub( frame ) local new_args = str._getParameters( frame.args, { 's', 'i', 'j' } ); local s = new_args['s'] or ''; local i = tonumber( new_args['i'] ) or 1; local j = tonumber( new_args['j'] ) or -1; local len = mw.ustring.len( s ); -- Convert negatives for range checking if i < 0 then i = len + i + 1; end if j < 0 then j = len + j + 1; end if i > len or j > len or i < 1 or j < 1 then return str._error( 'Значение индекса подстроки выходит за допустимые границы' ); end if j < i then return str._error( 'Неверный порядок индексов подстроки' ); end return mw.ustring.sub( s, i, j ) end --[[ This function implements that features of {{str sub old}} and is kept in order to maintain these older templates. ]] function str.sublength( frame ) local i = tonumber( frame.args.i ) or 0 local len = tonumber( frame.args.len ) return mw.ustring.sub( frame.args.s, i + 1, len and ( i + len ) ) end --[[ match This function returns a substring from the source string that matches a specified pattern. Usage: {{#invoke:String|match|source_string|pattern_string|start_index|match_number|plain_flag|nomatch_output}} OR {{#invoke:String|pos|s=source_string|pattern=pattern_string|start=start_index |match=match_number|plain=plain_flag|nomatch=nomatch_output}} Parameters s: The string to search pattern: The pattern or string to find within the string start: The index within the source string to start the search. The first character of the string has index 1. Defaults to 1. match: In some cases it may be possible to make multiple matches on a single string. This specifies which match to return, where the first match is match= 1. If a negative number is specified then a match is returned counting from the last match. Hence match = -1 is the same as requesting the last match. Defaults to 1. plain: A flag indicating that the pattern should be understood as plain text. Defaults to false. nomatch: If no match is found, output the "nomatch" value rather than an error. If invoked using named parameters, Mediawiki will automatically remove any leading or trailing whitespace from each string. In some circumstances this is desirable, in other cases one may want to preserve the whitespace. If the match_number or start_index are out of range for the string being queried, then this function generates an error. An error is also generated if no match is found. If one adds the parameter ignore_errors=true, then the error will be suppressed and an empty string will be returned on any failure. For information on constructing Lua patterns, a form of [regular expression], see: * http://www.lua.org/manual/5.1/manual.html#5.4.1 * http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Patterns * http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Ustring_patterns ]] function str.match( frame ) local new_args = str._getParameters( frame.args, {'s', 'pattern', 'start', 'match', 'plain', 'nomatch'} ); local s = new_args['s'] or ''; local start = tonumber( new_args['start'] ) or 1; local plain_flag = str._getBoolean( new_args['plain'] or false ); local pattern = new_args['pattern'] or ''; local match_index = math.floor( tonumber(new_args['match']) or 1 ); local nomatch = new_args['nomatch']; if s == '' then return str._error( 'Пустая строка поиска' ); end if pattern == '' then return str._error( 'Пустой шаблон поиска' ); end if math.abs(start) < 1 or math.abs(start) > mw.ustring.len( s ) then return str._error( 'Индекс начала поиска выходит за допустимые границы' ); end if match_index == 0 then return str._error( 'Индекс совпадения выходит за допустимые границы' ); end if plain_flag then pattern = str._escapePattern( pattern ); end local result if match_index == 1 then -- Find first match is simple case result = mw.ustring.match( s, pattern, start ) else if start > 1 then s = mw.ustring.sub( s, start ); end local iterator = mw.ustring.gmatch(s, pattern); if match_index > 0 then -- Forward search for w in iterator do match_index = match_index - 1; if match_index == 0 then result = w; break; end end else -- Reverse search local result_table = {}; local count = 1; for w in iterator do result_table[count] = w; count = count + 1; end result = result_table[ count + match_index ]; end end if result == nil then if nomatch == nil then return str._error( 'Совпадение не найдено' ); else return nomatch; end else return result; end end --[[ pos This function returns a single character from the target string at position pos. Usage: {{#invoke:String|pos|target_string|index_value}} OR {{#invoke:String|pos|target=target_string|pos=index_value}} Parameters target: The string to search pos: The index for the character to return If invoked using named parameters, Mediawiki will automatically remove any leading or trailing whitespace from the target string. In some circumstances this is desirable, in other cases one may want to preserve the whitespace. The first character has an index value of 1. If one requests a negative value, this function will select a character by counting backwards from the end of the string. In other words pos = -1 is the same as asking for the last character. A requested value of zero, or a value greater than the length of the string returns an error. ]] function str.pos( frame ) local new_args = str._getParameters( frame.args, {'target', 'pos'} ); local target_str = new_args['target'] or ''; local pos = tonumber( new_args['pos'] ) or 0; if pos == 0 or math.abs(pos) > mw.ustring.len( target_str ) then return str._error( 'Значение индекса строки выходит за допустимые границы' ); end return mw.ustring.sub( target_str, pos, pos ); end --[[ str_find This function duplicates the behavior of {{str_find}}, including all of its quirks. This is provided in order to support existing templates, but is NOT RECOMMENDED for new code and templates. New code is recommended to use the "find" function instead. Returns the first index in "source" that is a match to "target". Indexing is 1-based, and the function returns -1 if the "target" string is not present in "source". Important Note: If the "target" string is empty / missing, this function returns a value of "1", which is generally unexpected behavior, and must be accounted for separatetly. ]] function str.str_find( frame ) local new_args = str._getParameters( frame.args, {'source', 'target'} ); local source_str = new_args['source'] or ''; local target_str = new_args['target'] or ''; if target_str == '' then return 1; end local start = mw.ustring.find( source_str, target_str, 1, true ) if start == nil then start = -1 end return start end --[[ find This function allows one to search for a target string or pattern within another string. Usage: {{#invoke:String|find|source_str|target_string|start_index|plain_flag}} OR {{#invoke:String|find|source=source_str|target=target_str|start=start_index|plain=plain_flag}} Parameters source: The string to search target: The string or pattern to find within source start: The index within the source string to start the search, defaults to 1 plain: Boolean flag indicating that target should be understood as plain text and not as a Lua style regular expression, defaults to true If invoked using named parameters, Mediawiki will automatically remove any leading or trailing whitespace from the parameter. In some circumstances this is desirable, in other cases one may want to preserve the whitespace. This function returns the first index >= "start" where "target" can be found within "source". Indices are 1-based. If "target" is not found, then this function returns 0. If either "source" or "target" are missing / empty, this function also returns 0. This function should be safe for UTF-8 strings. ]] function str.find( frame ) local new_args = str._getParameters( frame.args, {'source', 'target', 'start', 'plain' } ); local source_str = new_args['source'] or ''; local pattern = new_args['target'] or ''; local start_pos = tonumber(new_args['start']) or 1; local plain = new_args['plain'] or true; if source_str == '' or pattern == '' then return 0; end plain = str._getBoolean( plain ); local start = mw.ustring.find( source_str, pattern, start_pos, plain ) if start == nil then start = 0 end return start end --[[ replace This function allows one to replace a target string or pattern within another string. Usage: {{#invoke:String|replace|source_str|pattern_string|replace_string|replacement_count|plain_flag}} OR {{#invoke:String|replace|source=source_string|pattern=pattern_string|replace=replace_string| count=replacement_count|plain=plain_flag}} Parameters source: The string to search pattern: The string or pattern to find within source replace: The replacement text count: The number of occurences to replace, defaults to all. plain: Boolean flag indicating that pattern should be understood as plain text and not as a Lua style regular expression, defaults to true ]] function str.replace( frame ) local new_args = str._getParameters( frame.args, {'source', 'pattern', 'replace', 'count', 'plain' } ); local source_str = new_args['source'] or ''; local pattern = new_args['pattern'] or ''; local replace = new_args['replace'] or ''; local count = tonumber( new_args['count'] ); local plain = new_args['plain'] or true; if source_str == '' or pattern == '' then return source_str; end plain = str._getBoolean( plain ); if plain then pattern = str._escapePattern( pattern ); replace = string.gsub( replace, "%%", "%%%%" ) --Only need to escape replacement sequences. end local result; if count ~= nil then result = mw.ustring.gsub( source_str, pattern, replace, count ); else result = mw.ustring.gsub( source_str, pattern, replace ); end return result; end --[[ This function adds support for escaping parts of the patterns when using [plain=false]. ]] function str.escape( frame ) local new_args = str._getParameters( frame.args, {'pattern' } ); local pattern = new_args['pattern'] or ''; local result = ''; result = str._escapePattern( pattern ); return result; end --[[ Internal compare string function ]] function str._strcmp(a , b) local s1c = mw.ustring.gcodepoint( a ); local s2c = mw.ustring.gcodepoint( b ); while true do local c1 = s1c(); local c2 = s2c(); if c1 == nil then if c2 == nil then return 0 else return -1 end else if c2 ~= nil then if c1 ~= c2 then return c1 < c2 and -1 or 1 end else return 1 end end end return 0 end --[[ compare This function compare two UTF-8 strings Usage: {{#invoke:String|compare|str1|str2}} Returns: 0 - if strings are equal 1 - if st1 > str2 -1 - if str1 < str2 ]] function str.compare(frame) local str1 = frame.args[1] or ''; local str2 = frame.args[2] or ''; return str._strcmp(str1 , str2) end --[[ simple function to pipe string.rep to templates. ]] function str.rep( frame ) local repetitions = tonumber( frame.args[2] ) if not repetitions then return str._error( 'функция rep ожидает число во втором параметре, а получено "' .. ( frame.args[2] or '' ) .. '"' ) end return string.rep( frame.args[1] or '', repetitions ) end --[[ Helper function that populates the argument list given that user may need to use a mix of named and unnamed parameters. This is relevant because named parameters are not identical to unnamed parameters due to string trimming, and when dealing with strings we sometimes want to either preserve or remove that whitespace depending on the application. ]] function str._getParameters( frame_args, arg_list ) local new_args = {}; local index = 1; local value; for i,arg in ipairs( arg_list ) do value = frame_args[arg] if value == nil then value = frame_args[index]; index = index + 1; end new_args[arg] = value; end return new_args; end --[[ Helper function to handle error messages. ]] function str._error( error_str ) local frame = mw.getCurrentFrame(); local error_category = frame.args.error_category or 'Страницы с ошибками модуля String'; local ignore_errors = frame.args.ignore_errors or false; local no_category = frame.args.no_category or false; if str._getBoolean(ignore_errors) then return ''; end local error_str = '<strong class="error">Ошибка модуля String: ' .. error_str .. '</strong>'; if error_category ~= '' and not str._getBoolean( no_category ) then error_str = '[[Категория:' .. error_category .. ']]' .. error_str; end return error_str; end --[[ Helper Function to interpret boolean strings ]] function str._getBoolean( boolean_str ) local boolean_value; if type( boolean_str ) == 'string' then boolean_str = boolean_str:lower(); if boolean_str == 'false' or boolean_str == 'no' or boolean_str == '0' or boolean_str == '' then boolean_value = false; else boolean_value = true; end elseif type( boolean_str ) == 'boolean' then boolean_value = boolean_str; else error( 'Логическое значение не найдено' ); end return boolean_value end --[[ Helper function that escapes all pattern characters so that they will be treated as plain text. ]] function str._escapePattern( pattern_str ) return ( string.gsub( pattern_str, "[%(%)%.%%%+%-%*%?%[%^%$%]]", "%%%0" ) ) end return str 2c7347f1dafbbc0efc196c148a1f81e7b82420dc Модуль:TemplateDataDoc 828 103 203 2024-11-22T13:56:09Z wikipedia:ru>Stjn 0 для примеров всё-таки не нужно Scribunto text/plain require( 'strict' ); local docSubPage = mw.message.new( 'Templatedata-doc-subpage' ):plain(); local p = {}; local lastNumber = 0; -- Enable/disable additional spacing for block-formatted templates local formatBlockSpaces = true; -- Params that should not be shown in code local deprecatedParams = { 'nocat', 'from', 'nocoord', 'nocatcoord', 'Автооформление заголовка', 'автооформление заголовка', 'Ширина', 'ширина', 'Ширина изображения', 'ширина изображения', 'Ширина логотипа', 'ширина логотипа', 'Ширина автографа', 'ширина автографа', }; local noDocNote = 'TemplateDataDoc: Запишите страницу для отображения заполненного шаблона.'; function p.processJson( json ) local status, data = pcall( mw.text.jsonDecode, json ); if status == false then return nil; end if not data[ 'paramOrder' ] then data[ 'paramOrder' ] = {}; for paramName, paramData in pairs( data[ 'params' ] ) do table.insert( data[ 'paramOrder' ], paramName ); end end for _, param in ipairs( deprecatedParams ) do if data[ 'params' ][ param ] ~= nil then data[ 'params' ][ param ][ 'deprecated' ] = '-'; end end return data; end function p.getTemplateData( pageName ) local title = mw.title.makeTitle( 0, pageName ); if not title or not title.exists then return false end local content = title:getContent() if not content then return false; end; local json = mw.ustring.match( content, '<[Tt]emplate[Dd]ata%s*>(.*)</[Tt]emplate[Dd]ata%s*>' ); if not json then return nil; end return p.processJson( json ) end function p.getValue( data, key ) if data[ key ] then return data[ key ]; end -- Numbered keys return as numbers local nkey = tonumber( key ); if nkey ~= nil and data[ nkey ] then return data[ nkey ]; end return {}; end -- See https://phabricator.wikimedia.org/diffusion/ETDA/browse/master/Specification.md?as=remarkup -- We need a global format value for the 'block' and 'inline': [[phab:T205438]] function p.convertFormatString( rawTemplateFormat ) local formatType = rawTemplateFormat or 'inline'; local templateFormat = formatType; local isBlockFormatted = false; if formatType == 'block' then templateFormat = '{{_\n| _ = _\n}}'; isBlockFormatted = true; elseif formatType == 'inline' then templateFormat = '{{_|_=_}}'; end return templateFormat, isBlockFormatted, formatType; end function p.getFormatParts( rawTemplateFormat, templateName ) local templateFormat, isBlockFormatted, formatType = p.convertFormatString( rawTemplateFormat ); local nameFormat = mw.ustring.match( templateFormat, '^[^|]+' ); local paramKeyFormat = mw.ustring.match( templateFormat, '%|[^=]+=' ); local paramValueFormat = mw.ustring.match( templateFormat, '=[^}]+' ); paramValueFormat = mw.ustring.sub( paramValueFormat, 2 ); local endFormat = mw.ustring.match( templateFormat, '%}%}.*$' ); local startFormat = mw.ustring.gsub( nameFormat, '_', templateName ); return isBlockFormatted, formatType, startFormat, endFormat, paramKeyFormat, paramValueFormat; end function p.formatKeyValue( key, parameterData, formatData ) if parameterData[ 'deprecated' ] then return ''; end local args = formatData.args; local parameterName = key; local nkey = tonumber( key ); -- Add additional spacing to string keys if formatBlockSpaces and formatData.parameterLength and formatData.formatType ~= 'inline' and ( nkey == nil or lastNumber ~= nkey - 1 ) then while mw.ustring.len( key ) < formatData.parameterLength do key = key .. ' '; end end -- Remove numbering for adjacent numbered keys if nkey ~= nil and lastNumber == nkey - 1 then key = ''; lastNumber = nkey; end local value = ''; if formatData.valueKey == 'example' and parameterData[ 'example' ] then -- Example value = parameterData[ 'example' ]; else if formatData.valueKey == 'description' and parameterData[ 'description' ] then -- Description value = parameterData[ 'description' ]; if value ~= '' then value = '<!-- ' .. value .. ' -->'; end elseif parameterData[ 'autovalue' ] then -- Autovalue value = parameterData[ 'autovalue' ]; end if args[ '$' .. parameterName ] and args[ '$' .. parameterName ] ~= '' then -- Custom values from template call value = args[ '$' .. parameterName ]; end end local formattedKey = mw.ustring.gsub( formatData.paramKeyFormat, '_+', key, 1 ); if key == '' then formattedKey = mw.ustring.gsub( formattedKey, '=', '' ); end return formattedKey .. mw.ustring.gsub( formatData.paramValueFormat, '_', value, 1 ); end function p.generateBlankCode( templateData, templateName, args ) if templateData == false then return '{{' .. templateName .. '}}'; end local parameterLength = 0; for i, parameterName in ipairs( templateData[ 'paramOrder' ] ) do local parameterData = p.getValue( templateData[ 'params' ], parameterName ); if not parameterData[ 'deprecated' ] then local length = mw.ustring.len( parameterName ); if length > parameterLength then parameterLength = length; end end end local isBlockFormatted, formatType, startFormat, endFormat, paramKeyFormat, paramValueFormat = p.getFormatParts( templateData[ 'format' ], templateName ); local out = startFormat; lastNumber = 0; for i, parameterName in ipairs( templateData[ 'paramOrder' ] ) do local parameterData = p.getValue( templateData[ 'params' ], parameterName ); if parameterData[ 'inherits' ] then parameterData = p.getValue( templateData[ 'params' ], parameterData[ 'inherits' ] ); end out = out .. p.formatKeyValue( parameterName, parameterData, { args = args, valueKey = ( args[ 'description' ] and 'description' or nil ), formatType = formatType, isBlockFormatted = isBlockFormatted, parameterLength = parameterLength, paramKeyFormat = paramKeyFormat, paramValueFormat = paramValueFormat, } ); end return out .. endFormat; end function p.generateBlank( frame ) local frame = mw.getCurrentFrame(); local getArgs = require( 'Module:Arguments' ).getArgs; local args = getArgs( frame ); local templateName = frame.args[ 1 ]; table.remove( args, 1 ); local docPage = 'Template:' .. templateName .. '/' .. docSubPage; local templateData = p.getTemplateData( docPage ); local out = p.generateBlankCode( templateData, templateName, args ); local previewNote = '' if templateData == false and frame:preprocess('{{REVISIONID}}') == '' then previewNote = '<div class="warningbox">' .. noDocNote .. '</div>'; end return previewNote .. frame:extensionTag{ name = 'syntaxhighlight', args = { lang = 'html', copy = true }, content = out, }; end function p.generateExampleCode( templateData, templateName, args ) if templateData == false then return '{{' .. templateName .. '}}'; end local parameterLength = 0; for i, parameterName in ipairs( templateData[ 'paramOrder' ] ) do local parameterData = p.getValue( templateData[ 'params' ], parameterName ); if parameterData[ 'example' ] and not parameterData[ 'deprecated' ] then local length = mw.ustring.len( parameterName ); if length > parameterLength then parameterLength = length; end end end local isBlockFormatted, formatType, startFormat, endFormat, paramKeyFormat, paramValueFormat = p.getFormatParts( templateData[ 'format' ], templateName ); local out = startFormat; lastNumber = 0; for i, parameterName in ipairs( templateData[ 'paramOrder' ] ) do local parameterData = p.getValue( templateData[ 'params' ], parameterName ); if parameterData[ 'inherits' ] then parameterData = p.getValue( templateData[ 'params' ], parameterData[ 'inherits' ] ); end if parameterData[ 'example' ] then out = out .. p.formatKeyValue( parameterName, parameterData, { args = args, valueKey = 'example', formatType = formatType, isBlockFormatted = isBlockFormatted, parameterLength = parameterLength, paramKeyFormat = paramKeyFormat, paramValueFormat = paramValueFormat, } ); end end return out .. endFormat; end function p.generateExample( frame ) local frame = mw.getCurrentFrame(); local args = frame.args; local templateName = frame.args[ 1 ]; local docPage = 'Template:' .. templateName .. '/' .. docSubPage; local templateData = p.getTemplateData( docPage ); local out = p.generateExampleCode( templateData, templateName, args ); local previewNote = '' if templateData == false and frame:preprocess('{{REVISIONID}}') == '' then previewNote = '<div class="warningbox">' .. noDocNote .. '</div>'; end return previewNote .. frame:preprocess( out ) .. frame:extensionTag{ name = 'syntaxhighlight', args = { lang = 'html' }, content = out, }; end return p; 8134c68a67c62ea08db535b9110981288d627bbd Модуль:Wikidata/config 828 34 65 2024-12-15T07:54:37Z wikipedia:ru>Putnik 0 на всякий случай, чтобы избежать ненужных сносок Scribunto text/plain -- Property configuration for Wikidata module return { global = { separator = ',&#32;', conjunction = '&#32;и&#32;', }, presets = { ['catonly'] = { datatype = 'wikibase-item', conjunction = '', invisible = true, ['value-module'] = 'Wikidata/item', ['value-function'] = 'formatCategoryOnly', references = '', category = 'P910', }, ['country'] = { datatype = 'wikibase-item', ['claim-module'] = 'Wikidata/Places', ['claim-function'] = 'formatCountryClaimWithFlag', before = '<ul><li>', separator = '</li><li>', conjunction = '</li><li>', after = '</li></ul>', }, ['from-to'] = { datatype = 'time', ['property-module'] = 'Wikidata/date', ['property-function'] = 'formatDateIntervalProperty', }, ['link'] = { ['value-module'] = 'Wikidata/link', ['value-function'] = 'fromModule', }, ['list'] = { before = '<ul><li>', separator = '</li><li>', conjunction = '</li><li>', after = '</li></ul>', }, ['name'] = { datatype = 'monolingualtext', monolingualLangTemplate = 'lang', separator = '<br>', conjunction = '<br>', }, ['place'] = { datatype = 'wikibase-item', ['claim-module'] = 'Wikidata/Places', ['claim-function'] = 'formatPlaceWithQualifiers', before = '<ul><li>', separator = '</li><li>', conjunction = '</li><li>', after = '</li></ul>', }, ['quantity (date)'] = { datatype = 'quantity', before = '<ul><li>', separator = '</li><li>', conjunction = '</li><li>', after = '</li></ul>', qualifier = 'P585', }, }, datatypes = { commonsMedia = { limit = 1, references = false, size = '274x400px', separator = '<br>', conjunction = '<br>', somevalue = '', ['value-module'] = 'Wikidata/media', ['value-function'] = 'formatCommonsMediaValue', }, ['external-id'] = { references = false, }, ['globe-coordinate'] = { limit = 1, references = false, }, url = { separator = '<br>', conjunction = '<br>', references = false, ['value-module'] = 'Wikidata/url', ['value-function'] = 'formatUrlValue', }, quantity = { siConversion = true } }, properties = { P6 = { datatype = 'wikibase-item', }, P17 = { preset = 'country', }, P18 = { datatype = 'commonsMedia', fixdouble = true, }, P19 = { preset = 'place', separator = ',</li><li>', conjunction = ' или </li><li>', }, P20 = { preset = 'place', separator = ',</li><li>', conjunction = ' или </li><li>', }, P22 = { datatype = 'wikibase-item', conjunction = ' или ' }, P25 = { datatype = 'wikibase-item', conjunction = ' или ' }, P26 = { datatype = 'wikibase-item', }, P27 = { preset = 'country', }, P31 = { datatype = 'wikibase-item', references = false, }, P37 = { datatype = 'wikibase-item', }, P39 = { datatype = 'wikibase-item', ['claim-module'] = 'Wikidata/positions', ['claim-function'] = 'formatPositionClaim', separator = '', conjunction = '', allowTables = true, }, P40 = { datatype = 'wikibase-item', }, P41 = { datatype = 'commonsMedia', size = '150x200px', }, P53 = { datatype = 'wikibase-item', category = 'P910', }, P54 = { category = 'P6112', }, P57 = { datatype = 'wikibase-item', preset = 'list', }, P58 = { datatype = 'wikibase-item', preset = 'list', }, P59 = { datatype = 'wikibase-item', category = 'P910', references = false, }, P69 = { datatype = 'wikibase-item', preset = 'list', category = 'P3876', qualifier = 'P582', }, P94 = { datatype = 'commonsMedia', size = '100x200px', }, P86 = { datatype = 'wikibase-item', preset = 'list', }, P101 = { datatype = 'wikibase-item', }, P102 = { datatype = 'wikibase-item', preset = 'list', qualifier = 'P582', category = 'P6365', }, P103 = { datatype = 'wikibase-item', }, P106 = { datatype = 'wikibase-item', ['claim-module'] = 'Wikidata/item', ['claim-function'] = 'formatEntityWithGenderClaim', conjunction = ',&#32;', }, P108 = { datatype = 'wikibase-item', preset = 'list', category = 'P4195', }, P109 = { datatype = 'commonsMedia', size = '150x150px', alt = 'Изображение автографа', }, P117 = { datatype = 'commonsMedia', size = '290x300px', alt = 'Изображение химической структуры', }, P119 = { preset = 'place', thisLocationOnly = 'true', }, P131 = { datatype = 'wikibase-item', }, P140 = { datatype = 'wikibase-item', }, P154 = { size = '220x80px', alt = 'Изображение логотипа', }, P159 = { preset = 'place', }, P161 = { preset = 'list', }, P162 = { preset = 'list', }, P163 = { datatype = 'wikibase-item', }, P166 = { datatype = 'wikibase-item', ['property-module'] = 'Wikidata/Medals', ['property-function'] = 'formatProperty', ['value-module'] = 'Wikidata/Medals', ['value-function'] = 'formatValue', before = '<div style="text-align:justify">', after = '</div>', separator = '&#32;', conjunction = '&#32;', references = false, allowTables = true, }, P190 = { datatype = 'wikibase-item', }, P212 = { preset = 'link', }, P225 = { preset = 'list', ['claim-module'] = 'Wikidata/Biology', ['claim-function'] = 'formatTaxonNameClaim', }, P237 = { datatype = 'wikibase-item', }, P241 = { datatype = 'wikibase-item', }, P242 = { datatype = 'commonsMedia', size = '300x300px', }, P247 = { formatter = 'https://nssdc.gsfc.nasa.gov/nmc/spacecraft/display.action?id=$1', }, P267 = { preset = 'link', }, P276 = { preset = 'place', }, P281 = { datatype = 'string', }, P286 = { preset = 'list', }, P296 = { formatter = 'http://osm.sbin.ru/esr/esr:$1', }, P301 = { rawArticle = true, }, P344 = { preset = 'list', }, P345 = { preset = 'link', }, P348 = { preset = 'list', ['property-module'] = 'Wikidata/Software', ['property-function'] = 'formatVersionProperty', }, P361 = { datatype = 'wikibase-item', }, P373 = { datatype = 'string', ['value-module'] = 'Wikidata/media', ['value-function'] = 'formatCommonsCategory', limit = 1, references = false, }, P374 = { datatype = 'external-id', }, P395 = { datatype = 'string', }, P407 = { datatype = 'wikibase-item', }, P410 = { datatype = 'wikibase-item', }, P412 = { datatype = 'wikibase-item', category = 'P910', }, P413 = { datatype = 'wikibase-item', ['claim-module'] = 'Wikidata/item', ['claim-function'] = 'formatEntityWithGenderClaim', conjunction = ',&#32;', category = 'P910', }, P414 = { ['claim-module'] = 'Wikidata/item', ['claim-function'] = 'applyDefaultTemplate', }, P421 = { datatype = 'wikibase-item', }, P473 = { datatype = 'string', }, P495 = { preset = 'country', }, P505 = { preset = 'list', }, P512 = { datatype = 'wikibase-item', ['property-module'] = 'Wikidata/P512', ['property-function'] = 'formatAcademicDegree', }, P527 = { preset = 'list', }, P528 = { references = false, qualifier = 'P972', }, P551 = { preset = 'place', }, P569 = { datatype = 'time', ['claim-module'] = 'Wikidata/date', ['claim-function'] = 'formatDateOfBirthClaim', }, P570 = { datatype = 'time', ['claim-module'] = 'Wikidata/date', ['claim-function'] = 'formatDateOfDeathClaim', }, P571 = { datatype = 'time', }, P576 = { datatype = 'time', }, P598 = { datatype = 'wikibase-item', }, P607 = { datatype = 'wikibase-item', preset = 'list', }, P625 = { datatype = 'globe-coordinate', }, P669 = { qualifier = 'P670', }, P685 = { formatter = 'https://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=$1', }, P721 = { preset = 'link', }, P764 = { preset = 'link', }, P803 = { datatype = 'wikibase-item', }, P856 = { datatype = 'url', }, P881 = { novalue = 'нет', category = 'P910', }, P884 = { preset = 'link', }, P915 = { category = 'P1740', }, P957 = { preset = 'link', }, P972 = { preset = 'catonly', }, P1077 = { preset = 'link', }, P1082 = { preset = 'quantity (date)', unit = 'чел.', ['property-module'] = 'Wikidata/number', ['property-function'] = 'formatPropertyWithMostRecentClaimAndIndicator' }, P1098 = { preset = 'quantity (date)', unit = 'чел.', }, P1120 = { preset = 'quantity (date)', unit = 'чел.', ['property-module'] = 'Wikidata/number', ['property-function'] = 'formatPropertyWithMostRecentClaimAndIndicator' }, P1128 = { datatype = 'quantity', preset = 'quantity (date)', unit = 'чел.', ['property-module'] = 'Wikidata/number', ['property-function'] = 'formatPropertyWithMostRecentClaimAndIndicator' }, P1114 = { datatype = 'quantity', qualifier = 'P585', }, P1174 = { preset = 'quantity (date)', unit = 'чел.', }, P1195 = { ['value-module'] = 'Wikidata/Software', ['value-function'] = 'formatExtension', conjunction = ' или ', }, P1215 = { datatype = 'quantity', ['property-module'] = 'Wikidata/number', ['property-function'] = 'formatVisualMagnitude' }, P1246 = { preset = 'link', }, P1249 = { datatype = 'time', }, P1352 = { preset = 'quantity (date)', }, P1376 = { datatype = 'wikibase-item', }, P1402 = { preset = 'link', }, P1448 = { preset = 'name', }, P1458 = { datatype = 'quantity', ['property-module'] = 'Wikidata/number', ['property-function'] = 'formatColorIndex' }, P1464 = { datatype = 'wikibase-item', }, P1476 = { preset = 'name', }, P1477 = { preset = 'name', }, P1532 = { preset = 'country', rank = '[rank:normal, rank:preferred]', }, P1543 = { datatype = 'commonsMedia', }, P1559 = { preset = 'name', }, P1603 = { preset = 'quantity (date)', unit = 'чел.', ['property-module'] = 'Wikidata/number', ['property-function'] = 'formatPropertyWithMostRecentClaimAndIndicator' }, P1621 = { size = '300x300px', }, P1692 = { preset = 'link', }, P1705 = { preset = 'name', }, P1753 = { rowArticle = true, }, P1809 = { preset = 'list', }, P1846 = { datatype = 'commonsMedia', fixdouble = true, }, P2031 = { preset = 'from-to', to = 'P2032', within = 'P570', }, P2043 = { preset = 'quantity (date)', }, P2044 = { datatype = 'quantity', }, P2046 = { preset = 'quantity (date)', siConversion = false, }, P2047 = { siConversion = false, }, P2048 = { conjunction = '&#32;или&#32;', }, P2060 = { siConversion = false, }, P2097 = { siConversion = false, }, P2120 = { siConversion = false, }, P2137 = { preset = 'quantity (date)', ['property-module'] = 'Wikidata/number', ['property-function'] = 'formatPropertyWithMostRecentClaimAndIndicator', countByThousands = true, }, P2139 = { preset = 'quantity (date)', ['property-module'] = 'Wikidata/number', ['property-function'] = 'formatPropertyWithMostRecentClaimAndIndicator', countByThousands = true, }, P2146 = { siConversion = false, }, P2214 = { siConversion = false }, P2226 = { preset = 'quantity (date)', ['property-module'] = 'Wikidata/number', ['property-function'] = 'formatPropertyWithMostRecentClaimAndIndicator', countByThousands = true, }, P2257 = { siConversion = false }, P2260 = { siConversion = false }, P2295 = { preset = 'quantity (date)', ['property-module'] = 'Wikidata/number', ['property-function'] = 'formatPropertyWithMostRecentClaimAndIndicator', countByThousands = true, }, P2324 = { datatype = 'quantity', preset = 'quantity (date)', unit = 'чел.' }, P2403 = { preset = 'quantity (date)', ['property-module'] = 'Wikidata/number', ['property-function'] = 'formatPropertyWithMostRecentClaimAndIndicator', countByThousands = true, }, P2425 = { alt = 'Изображение орденской планки', }, P2583 = { siConversion = false, }, P2597 = { preset = 'catonly', }, P2650 = { datatype = 'wikibase-item', }, P2789 = { preset = 'list', }, P2896 = { siConversion = false, }, P2910 = { size = '100x80px', }, P3083 = { formatter = 'http://simbad.u-strasbg.fr/simbad/sim-id?Ident=$1', }, P3086 = { siConversion = false, }, P3362 = { preset = 'quantity (date)', ['property-module'] = 'Wikidata/number', ['property-function'] = 'formatPropertyWithMostRecentClaimAndIndicator', countByThousands = true, }, P4614 = { category = 'P1200', }, P5348 = { siConversion = false, }, P6257 = { ['value-module'] = 'Wikidata/number', ['value-function'] = 'formatRA', }, P6258 = { ['value-module'] = 'Wikidata/number', ['value-function'] = 'formatDMS', }, P6259 = { ['references'] = false, }, P7584 = { siConversion = false, }, P8010 = { datatype = 'quantity', preset = 'quantity (date)', unit = 'чел.', ['property-module'] = 'Wikidata/number', ['property-function'] = 'formatPropertyWithMostRecentClaimAndIndicator' }, P8224 = { alt = 'Изображение молекулярной модели', }, }, categories = { ['links-to-entities-with-missing-label'] = 'Википедия:Статьи со ссылками на элементы Викиданных без подписи', ['links-to-entities-with-wikibase-error'] = 'Википедия:Страницы с ошибками скриптов, использующих Викиданные', ['links-to-entities-with-missing-local-language-label'] = 'Википедия:Статьи со ссылками на элементы Викиданных без русской подписи', ['media-contains-local-caption'] = 'Википедия:Локальная подпись у изображения из Викиданных', ['media-contains-markup'] = 'Википедия:Статьи с вики-разметкой в изображении карточки', ['media-contains-local-double'] = 'Википедия:Изображение в статье дублирует изображение в карточке', ['value-contains-table'] = 'Википедия:Статьи с табличной вставкой в карточке', }, errors = { ['property-param-not-provided'] = 'Не дан параметр свойства', ['entity-not-found'] = 'Сущность не найдена.', ['unknown-claim-type'] = 'Неизвестный тип заявления.', ['unknown-snak-type'] = 'Неизвестный тип снэка.', ['unknown-datavalue-type'] = 'Неизвестный тип значения данных.', ['unknown-entity-type'] = 'Неизвестный тип сущности.', ['unknown-property-module'] = 'Вы должны установить и property-module, и property-function.', ['unknown-claim-module'] = 'Вы должны установить и claim-module, и claim-function.', ['unknown-value-module'] = 'Вы должны установить и value-module, и value-function.', ['property-module-not-found'] = 'Модуль для отображения свойства не найден', ['property-function-not-found'] = 'Функция для отображения свойства не найдена', ['claim-module-not-found'] = 'Модуль для отображения утверждения не найден.', ['claim-function-not-found'] = 'Функция для отображения утверждения не найдена.', ['value-module-not-found'] = 'Модуль для отображения значения не найден.', ['value-function-not-found'] = 'Функция для отображения значения не найдена.', }, i18n = { somevalue = "''неизвестно''", novalue = '', -- Обстоятельства источника Q5727902 = 'около ', Q18122778 = '<span style="border-bottom: 1px dotted; cursor: help;" title="предположительно">предп.</span> ', Q30230067 = 'возможно ', Q52834024 = '<span style="border-bottom: 1px dotted; cursor: help;" title="менее чем">&lt;</span> ', Q54418095 = '<span style="border-bottom: 1px dotted; cursor: help;" title="более чем">&gt;</span> ', Q60070514 = 'примерно ', thousandPowers = {'', ' тыс.', ' млн', ' млрд', ' трлн'}, }, deprecatedSources = { Q355 = true, -- Facebook Q36578 = true, -- Gemeinsame Normdatei Q63056 = true, -- Find a Grave Q212256 = true, -- АиФ Q504063 = true, -- Discogs Q523660 = true, -- International Music Score Library Project by https://ru.wikipedia.org/?diff=107090748 Q1798125 = true, -- LIBRIS Q2621214 = true, -- Geni Q15222191 = true, -- BNF Q15241312 = true, -- Freebase Q19938912 = true, -- BNF Q21697707 = true, -- Хайазг Q25328680 = true, -- Prabook Q29861311 = true, -- SNAC Q86999151 = true, -- WeChangEd }, }; bd6091486f675bebf109cb52de53a162b05a5243 66 65 2025-01-25T21:00:18Z Vallenland 2 1 версия импортирована Scribunto text/plain -- Property configuration for Wikidata module return { global = { separator = ',&#32;', conjunction = '&#32;и&#32;', }, presets = { ['catonly'] = { datatype = 'wikibase-item', conjunction = '', invisible = true, ['value-module'] = 'Wikidata/item', ['value-function'] = 'formatCategoryOnly', references = '', category = 'P910', }, ['country'] = { datatype = 'wikibase-item', ['claim-module'] = 'Wikidata/Places', ['claim-function'] = 'formatCountryClaimWithFlag', before = '<ul><li>', separator = '</li><li>', conjunction = '</li><li>', after = '</li></ul>', }, ['from-to'] = { datatype = 'time', ['property-module'] = 'Wikidata/date', ['property-function'] = 'formatDateIntervalProperty', }, ['link'] = { ['value-module'] = 'Wikidata/link', ['value-function'] = 'fromModule', }, ['list'] = { before = '<ul><li>', separator = '</li><li>', conjunction = '</li><li>', after = '</li></ul>', }, ['name'] = { datatype = 'monolingualtext', monolingualLangTemplate = 'lang', separator = '<br>', conjunction = '<br>', }, ['place'] = { datatype = 'wikibase-item', ['claim-module'] = 'Wikidata/Places', ['claim-function'] = 'formatPlaceWithQualifiers', before = '<ul><li>', separator = '</li><li>', conjunction = '</li><li>', after = '</li></ul>', }, ['quantity (date)'] = { datatype = 'quantity', before = '<ul><li>', separator = '</li><li>', conjunction = '</li><li>', after = '</li></ul>', qualifier = 'P585', }, }, datatypes = { commonsMedia = { limit = 1, references = false, size = '274x400px', separator = '<br>', conjunction = '<br>', somevalue = '', ['value-module'] = 'Wikidata/media', ['value-function'] = 'formatCommonsMediaValue', }, ['external-id'] = { references = false, }, ['globe-coordinate'] = { limit = 1, references = false, }, url = { separator = '<br>', conjunction = '<br>', references = false, ['value-module'] = 'Wikidata/url', ['value-function'] = 'formatUrlValue', }, quantity = { siConversion = true } }, properties = { P6 = { datatype = 'wikibase-item', }, P17 = { preset = 'country', }, P18 = { datatype = 'commonsMedia', fixdouble = true, }, P19 = { preset = 'place', separator = ',</li><li>', conjunction = ' или </li><li>', }, P20 = { preset = 'place', separator = ',</li><li>', conjunction = ' или </li><li>', }, P22 = { datatype = 'wikibase-item', conjunction = ' или ' }, P25 = { datatype = 'wikibase-item', conjunction = ' или ' }, P26 = { datatype = 'wikibase-item', }, P27 = { preset = 'country', }, P31 = { datatype = 'wikibase-item', references = false, }, P37 = { datatype = 'wikibase-item', }, P39 = { datatype = 'wikibase-item', ['claim-module'] = 'Wikidata/positions', ['claim-function'] = 'formatPositionClaim', separator = '', conjunction = '', allowTables = true, }, P40 = { datatype = 'wikibase-item', }, P41 = { datatype = 'commonsMedia', size = '150x200px', }, P53 = { datatype = 'wikibase-item', category = 'P910', }, P54 = { category = 'P6112', }, P57 = { datatype = 'wikibase-item', preset = 'list', }, P58 = { datatype = 'wikibase-item', preset = 'list', }, P59 = { datatype = 'wikibase-item', category = 'P910', references = false, }, P69 = { datatype = 'wikibase-item', preset = 'list', category = 'P3876', qualifier = 'P582', }, P94 = { datatype = 'commonsMedia', size = '100x200px', }, P86 = { datatype = 'wikibase-item', preset = 'list', }, P101 = { datatype = 'wikibase-item', }, P102 = { datatype = 'wikibase-item', preset = 'list', qualifier = 'P582', category = 'P6365', }, P103 = { datatype = 'wikibase-item', }, P106 = { datatype = 'wikibase-item', ['claim-module'] = 'Wikidata/item', ['claim-function'] = 'formatEntityWithGenderClaim', conjunction = ',&#32;', }, P108 = { datatype = 'wikibase-item', preset = 'list', category = 'P4195', }, P109 = { datatype = 'commonsMedia', size = '150x150px', alt = 'Изображение автографа', }, P117 = { datatype = 'commonsMedia', size = '290x300px', alt = 'Изображение химической структуры', }, P119 = { preset = 'place', thisLocationOnly = 'true', }, P131 = { datatype = 'wikibase-item', }, P140 = { datatype = 'wikibase-item', }, P154 = { size = '220x80px', alt = 'Изображение логотипа', }, P159 = { preset = 'place', }, P161 = { preset = 'list', }, P162 = { preset = 'list', }, P163 = { datatype = 'wikibase-item', }, P166 = { datatype = 'wikibase-item', ['property-module'] = 'Wikidata/Medals', ['property-function'] = 'formatProperty', ['value-module'] = 'Wikidata/Medals', ['value-function'] = 'formatValue', before = '<div style="text-align:justify">', after = '</div>', separator = '&#32;', conjunction = '&#32;', references = false, allowTables = true, }, P190 = { datatype = 'wikibase-item', }, P212 = { preset = 'link', }, P225 = { preset = 'list', ['claim-module'] = 'Wikidata/Biology', ['claim-function'] = 'formatTaxonNameClaim', }, P237 = { datatype = 'wikibase-item', }, P241 = { datatype = 'wikibase-item', }, P242 = { datatype = 'commonsMedia', size = '300x300px', }, P247 = { formatter = 'https://nssdc.gsfc.nasa.gov/nmc/spacecraft/display.action?id=$1', }, P267 = { preset = 'link', }, P276 = { preset = 'place', }, P281 = { datatype = 'string', }, P286 = { preset = 'list', }, P296 = { formatter = 'http://osm.sbin.ru/esr/esr:$1', }, P301 = { rawArticle = true, }, P344 = { preset = 'list', }, P345 = { preset = 'link', }, P348 = { preset = 'list', ['property-module'] = 'Wikidata/Software', ['property-function'] = 'formatVersionProperty', }, P361 = { datatype = 'wikibase-item', }, P373 = { datatype = 'string', ['value-module'] = 'Wikidata/media', ['value-function'] = 'formatCommonsCategory', limit = 1, references = false, }, P374 = { datatype = 'external-id', }, P395 = { datatype = 'string', }, P407 = { datatype = 'wikibase-item', }, P410 = { datatype = 'wikibase-item', }, P412 = { datatype = 'wikibase-item', category = 'P910', }, P413 = { datatype = 'wikibase-item', ['claim-module'] = 'Wikidata/item', ['claim-function'] = 'formatEntityWithGenderClaim', conjunction = ',&#32;', category = 'P910', }, P414 = { ['claim-module'] = 'Wikidata/item', ['claim-function'] = 'applyDefaultTemplate', }, P421 = { datatype = 'wikibase-item', }, P473 = { datatype = 'string', }, P495 = { preset = 'country', }, P505 = { preset = 'list', }, P512 = { datatype = 'wikibase-item', ['property-module'] = 'Wikidata/P512', ['property-function'] = 'formatAcademicDegree', }, P527 = { preset = 'list', }, P528 = { references = false, qualifier = 'P972', }, P551 = { preset = 'place', }, P569 = { datatype = 'time', ['claim-module'] = 'Wikidata/date', ['claim-function'] = 'formatDateOfBirthClaim', }, P570 = { datatype = 'time', ['claim-module'] = 'Wikidata/date', ['claim-function'] = 'formatDateOfDeathClaim', }, P571 = { datatype = 'time', }, P576 = { datatype = 'time', }, P598 = { datatype = 'wikibase-item', }, P607 = { datatype = 'wikibase-item', preset = 'list', }, P625 = { datatype = 'globe-coordinate', }, P669 = { qualifier = 'P670', }, P685 = { formatter = 'https://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=$1', }, P721 = { preset = 'link', }, P764 = { preset = 'link', }, P803 = { datatype = 'wikibase-item', }, P856 = { datatype = 'url', }, P881 = { novalue = 'нет', category = 'P910', }, P884 = { preset = 'link', }, P915 = { category = 'P1740', }, P957 = { preset = 'link', }, P972 = { preset = 'catonly', }, P1077 = { preset = 'link', }, P1082 = { preset = 'quantity (date)', unit = 'чел.', ['property-module'] = 'Wikidata/number', ['property-function'] = 'formatPropertyWithMostRecentClaimAndIndicator' }, P1098 = { preset = 'quantity (date)', unit = 'чел.', }, P1120 = { preset = 'quantity (date)', unit = 'чел.', ['property-module'] = 'Wikidata/number', ['property-function'] = 'formatPropertyWithMostRecentClaimAndIndicator' }, P1128 = { datatype = 'quantity', preset = 'quantity (date)', unit = 'чел.', ['property-module'] = 'Wikidata/number', ['property-function'] = 'formatPropertyWithMostRecentClaimAndIndicator' }, P1114 = { datatype = 'quantity', qualifier = 'P585', }, P1174 = { preset = 'quantity (date)', unit = 'чел.', }, P1195 = { ['value-module'] = 'Wikidata/Software', ['value-function'] = 'formatExtension', conjunction = ' или ', }, P1215 = { datatype = 'quantity', ['property-module'] = 'Wikidata/number', ['property-function'] = 'formatVisualMagnitude' }, P1246 = { preset = 'link', }, P1249 = { datatype = 'time', }, P1352 = { preset = 'quantity (date)', }, P1376 = { datatype = 'wikibase-item', }, P1402 = { preset = 'link', }, P1448 = { preset = 'name', }, P1458 = { datatype = 'quantity', ['property-module'] = 'Wikidata/number', ['property-function'] = 'formatColorIndex' }, P1464 = { datatype = 'wikibase-item', }, P1476 = { preset = 'name', }, P1477 = { preset = 'name', }, P1532 = { preset = 'country', rank = '[rank:normal, rank:preferred]', }, P1543 = { datatype = 'commonsMedia', }, P1559 = { preset = 'name', }, P1603 = { preset = 'quantity (date)', unit = 'чел.', ['property-module'] = 'Wikidata/number', ['property-function'] = 'formatPropertyWithMostRecentClaimAndIndicator' }, P1621 = { size = '300x300px', }, P1692 = { preset = 'link', }, P1705 = { preset = 'name', }, P1753 = { rowArticle = true, }, P1809 = { preset = 'list', }, P1846 = { datatype = 'commonsMedia', fixdouble = true, }, P2031 = { preset = 'from-to', to = 'P2032', within = 'P570', }, P2043 = { preset = 'quantity (date)', }, P2044 = { datatype = 'quantity', }, P2046 = { preset = 'quantity (date)', siConversion = false, }, P2047 = { siConversion = false, }, P2048 = { conjunction = '&#32;или&#32;', }, P2060 = { siConversion = false, }, P2097 = { siConversion = false, }, P2120 = { siConversion = false, }, P2137 = { preset = 'quantity (date)', ['property-module'] = 'Wikidata/number', ['property-function'] = 'formatPropertyWithMostRecentClaimAndIndicator', countByThousands = true, }, P2139 = { preset = 'quantity (date)', ['property-module'] = 'Wikidata/number', ['property-function'] = 'formatPropertyWithMostRecentClaimAndIndicator', countByThousands = true, }, P2146 = { siConversion = false, }, P2214 = { siConversion = false }, P2226 = { preset = 'quantity (date)', ['property-module'] = 'Wikidata/number', ['property-function'] = 'formatPropertyWithMostRecentClaimAndIndicator', countByThousands = true, }, P2257 = { siConversion = false }, P2260 = { siConversion = false }, P2295 = { preset = 'quantity (date)', ['property-module'] = 'Wikidata/number', ['property-function'] = 'formatPropertyWithMostRecentClaimAndIndicator', countByThousands = true, }, P2324 = { datatype = 'quantity', preset = 'quantity (date)', unit = 'чел.' }, P2403 = { preset = 'quantity (date)', ['property-module'] = 'Wikidata/number', ['property-function'] = 'formatPropertyWithMostRecentClaimAndIndicator', countByThousands = true, }, P2425 = { alt = 'Изображение орденской планки', }, P2583 = { siConversion = false, }, P2597 = { preset = 'catonly', }, P2650 = { datatype = 'wikibase-item', }, P2789 = { preset = 'list', }, P2896 = { siConversion = false, }, P2910 = { size = '100x80px', }, P3083 = { formatter = 'http://simbad.u-strasbg.fr/simbad/sim-id?Ident=$1', }, P3086 = { siConversion = false, }, P3362 = { preset = 'quantity (date)', ['property-module'] = 'Wikidata/number', ['property-function'] = 'formatPropertyWithMostRecentClaimAndIndicator', countByThousands = true, }, P4614 = { category = 'P1200', }, P5348 = { siConversion = false, }, P6257 = { ['value-module'] = 'Wikidata/number', ['value-function'] = 'formatRA', }, P6258 = { ['value-module'] = 'Wikidata/number', ['value-function'] = 'formatDMS', }, P6259 = { ['references'] = false, }, P7584 = { siConversion = false, }, P8010 = { datatype = 'quantity', preset = 'quantity (date)', unit = 'чел.', ['property-module'] = 'Wikidata/number', ['property-function'] = 'formatPropertyWithMostRecentClaimAndIndicator' }, P8224 = { alt = 'Изображение молекулярной модели', }, }, categories = { ['links-to-entities-with-missing-label'] = 'Википедия:Статьи со ссылками на элементы Викиданных без подписи', ['links-to-entities-with-wikibase-error'] = 'Википедия:Страницы с ошибками скриптов, использующих Викиданные', ['links-to-entities-with-missing-local-language-label'] = 'Википедия:Статьи со ссылками на элементы Викиданных без русской подписи', ['media-contains-local-caption'] = 'Википедия:Локальная подпись у изображения из Викиданных', ['media-contains-markup'] = 'Википедия:Статьи с вики-разметкой в изображении карточки', ['media-contains-local-double'] = 'Википедия:Изображение в статье дублирует изображение в карточке', ['value-contains-table'] = 'Википедия:Статьи с табличной вставкой в карточке', }, errors = { ['property-param-not-provided'] = 'Не дан параметр свойства', ['entity-not-found'] = 'Сущность не найдена.', ['unknown-claim-type'] = 'Неизвестный тип заявления.', ['unknown-snak-type'] = 'Неизвестный тип снэка.', ['unknown-datavalue-type'] = 'Неизвестный тип значения данных.', ['unknown-entity-type'] = 'Неизвестный тип сущности.', ['unknown-property-module'] = 'Вы должны установить и property-module, и property-function.', ['unknown-claim-module'] = 'Вы должны установить и claim-module, и claim-function.', ['unknown-value-module'] = 'Вы должны установить и value-module, и value-function.', ['property-module-not-found'] = 'Модуль для отображения свойства не найден', ['property-function-not-found'] = 'Функция для отображения свойства не найдена', ['claim-module-not-found'] = 'Модуль для отображения утверждения не найден.', ['claim-function-not-found'] = 'Функция для отображения утверждения не найдена.', ['value-module-not-found'] = 'Модуль для отображения значения не найден.', ['value-function-not-found'] = 'Функция для отображения значения не найдена.', }, i18n = { somevalue = "''неизвестно''", novalue = '', -- Обстоятельства источника Q5727902 = 'около ', Q18122778 = '<span style="border-bottom: 1px dotted; cursor: help;" title="предположительно">предп.</span> ', Q30230067 = 'возможно ', Q52834024 = '<span style="border-bottom: 1px dotted; cursor: help;" title="менее чем">&lt;</span> ', Q54418095 = '<span style="border-bottom: 1px dotted; cursor: help;" title="более чем">&gt;</span> ', Q60070514 = 'примерно ', thousandPowers = {'', ' тыс.', ' млн', ' млрд', ' трлн'}, }, deprecatedSources = { Q355 = true, -- Facebook Q36578 = true, -- Gemeinsame Normdatei Q63056 = true, -- Find a Grave Q212256 = true, -- АиФ Q504063 = true, -- Discogs Q523660 = true, -- International Music Score Library Project by https://ru.wikipedia.org/?diff=107090748 Q1798125 = true, -- LIBRIS Q2621214 = true, -- Geni Q15222191 = true, -- BNF Q15241312 = true, -- Freebase Q19938912 = true, -- BNF Q21697707 = true, -- Хайазг Q25328680 = true, -- Prabook Q29861311 = true, -- SNAC Q86999151 = true, -- WeChangEd }, }; bd6091486f675bebf109cb52de53a162b05a5243 Модуль:Wikidata/Interproject 828 57 111 2025-01-02T18:27:53Z wikipedia:ru>MBH 0 запрос Каганера Scribunto text/plain local p = {} function p.getWikivoyageLink( context ) return p.getSisterProjectLink( 'voy', 'wikivoyage', context ) end function p.getWikibooksLink( context ) return p.getSisterProjectLink( 'b', 'wikibooks', context ) end function p.getWikiquoteLink( context ) return p.getSisterProjectLink( 'q', 'wikiquote', context ) end function p.getWikisourceLink( context ) return p.getSisterProjectLink( 's', 'wikisource', context ) end function p.getWikipediaLink( context ) return p.getSisterProjectLink( 'w', 'wiki', context ) end function p.getWiktionaryLink( context ) return p.getSisterProjectLink( 'wikt', 'wiktionary', context ) end function p.getSisterProjectLink( projectInterwikiPrefix, projectName, context ) -- проброс параметра from откуда угодно local entityId = nil local p_context = context while p_context do if p_context.args and p_context.args.from and p_context.args.from ~= '' then if p_context.args.from == '-' then return '' end entityId = p_context.args.from else entityId = mw.wikibase.getEntityIdForCurrentPage() end p_context = p_context:getParent() end -- По умолчанию старается достать ссылку на русском, иначе - на родном (P103) local wbStatus, sitelink = pcall( mw.wikibase.getSitelink, entityId, 'ru' .. projectName ) if wbStatus and sitelink then return projectInterwikiPrefix .. ':' .. sitelink end local wbStatus, langClaims = pcall( mw.wikibase.getBestStatements, entityId, 'P103' ) if wbStatus ~= true or not langClaims then return '' end local codes = mw.loadData( 'Module:Wikidata:Dictionary/P424' ) for _, claim in ipairs( langClaims ) do if claim.mainsnak and claim.mainsnak.datavalue and claim.mainsnak.datavalue.value and claim.mainsnak.datavalue.value.id then local codesById = codes[ claim.mainsnak.datavalue.value.id ] if codesById then for _, code in ipairs( codesById ) do wbStatus, sitelink = pcall( mw.wikibase.getSitelink, entityId, code .. projectName ) if wbStatus and sitelink then return projectInterwikiPrefix .. ':' .. code .. ':' .. sitelink end end end end end return '' end return p 48f3bdd682abd29718705f19e0411be2db6490cd Шаблон:Doc 10 82 161 2025-01-07T17:31:17Z wikipedia:ru>Stjn 0 не проверять страницы в основном пространстве на существование wikitext text/x-wiki <includeonly>{{doc/begin|{{SUBJECTSPACE}}:{{PAGENAME:{{{1|{{SUBJECTPAGENAME}}/doc}}}}}}} {{#if: {{{1|}}} | {{#ifexist: {{#if: {{NAMESPACE:{{{1}}}}} | {{{1}}} | {{SUBJECTSPACE}}:{{{1}}} }} | {{{{{1}}}|{{{2|}}}|{{{3|}}}|{{{4|}}}|{{{5|}}}}} | {{#ifexist: {{SUBJECTSPACE}}:{{{1}}} | {{{{{1}}}|{{{2|}}}|{{{3|}}}|{{{4|}}}|{{{5|}}}}} | {{Документировать|{{{1}}}}} }} }} | {{#ifexist: {{SUBJECTPAGENAME}}/doc | {{{{SUBJECTPAGENAME}}/doc}} | {{Документировать|{{SUBJECTPAGENAME}}/doc}} }} }} {{doc/end}}</includeonly><noinclude> {{doc}} </noinclude> 7298506ab2882f16fe7a52e0e080b2780b237bb9 Заглавная страница 0 1 1 2025-01-25T17:22:37Z MediaWiki default 1 Создать главную страницу wikitext text/x-wiki __NOTOC__ == Добро пожаловать в {{SITENAME}}! == Эта главная страница была создана автоматически и, похоже, ещё не заменена. === Для бюрократа(-ов) этой вики === Здравствуйте и добро пожаловать на вашу новую вики! Благодарим Вас за выбор Miraheze в качестве хостинга, и мы надеемся, что вы будете пользоваться нашими услугами. Вы можете сразу же начать работать над вашем вики-сайтов, как только пожелаете. Нужна помощь? Нет проблем! Мы поможем вам с вашей вики по мере необходимости. Для того, чтобы начать, мы добавили несколько ссылок о работе с MediaWiki: * [[mw:Special:MyLanguage/Help:Contents|Обсуждение руководства MediaWiki (например, навигация, редактирование, удаление страниц, блокирование пользователей)]] * [[meta:Special:MyLanguage/FAQ|ЧЗВ по Miraheze]] * [[meta:Special:MyLanguage/Request features|Запрос изменений настроек вашей вики.]] (Изменения расширений, оформления и логотипа/фавикона должны выполняться через [[Special:ManageWiki]] в вашей вики, см. [[meta:Special:MyLanguage/ManageWiki|ManageWiki]] для получения дополнительной информации.) ==== Но, Miraheze, я всё ещё не понимаю X! ==== Что ж, это не проблема. Даже если что-то не описано в документации/ЧЗВ, мы всё равно будем рады помочь вам. Вы можете найти нас здесь: * [[meta:Special:MyLanguage/Help center|На нашем собственном Miraheze вики]] * На [[phorge:|Phorge]] * На нашем [https://miraheze.org/discord Discord-сервере] * На IRC в #miraheze в irc.libera.chat (irc.libera.chat ([irc://irc.libera.chat/%23miraheze direct link]; [https://web.libera.chat/?channel=#miraheze вебчат])) === Для посетителя этой вики === Здравствуйте, заглавная страница по умолчанию ещё не была заменена бюрократом(-ами) этой вики. Возможно, администрация этого сайта разрабатывает эту страницу, поэтому мы рекомендуем вам зайти чуть позже. da708791005da529f6c1fffe139a9b3660d023e2 2 1 2025-01-25T19:12:51Z Vallenland 2 wikitext text/x-wiki __NOTOC__ <div style="border: solid black; background: rgb(100,100,100); background: radial-gradient(circle, rgba(127,201,255,1) 50%, rgba(82,127,63,1) 100%); color: white; text-align: center;"><big>'''Добро пожаловать на Валленланд Вики, энциклопедию о микрогосударстве Валленланд.'''</big> Валленланд - микрогосударство на части территории города Пскова одноимённой области в России. Оно было основано в 2025 году и активно развивается. </div> <div style="border: solid black; background: rgb(100,100,100); background: radial-gradient(circle, rgba(127,201,255,1) 50%, rgba(82,127,63,1) 100%); color: white; text-align: center; flex: 1; margin: 2px; display: block;">'''Статьи, которые следует прочитать...''' [[Справка:Что такое Валленланд|Простым людям]]ㅤㅤ [[Справка:Как доказать гражданство для вики|Гражданам Валленланда]]ㅤㅤ [[Справка:Установка дипломатических отношений|Главам микронаций]] [[Справка:Как получить гражданство|Желающим получить гражданство Валленланда]]</div> <div style="border: solid black; background: rgb(100,100,100); background: radial-gradient(circle, rgba(127,201,255,1) 50%, rgba(82,127,63,1) 100%); color: white; text-align: center; flex: 1; margin: 2px; display: block;">'''Избранная статья''' Тут ее пока нету но скоро будет </div> 0135b05ca03063d50cf606bc46df5da4cb862321 3 2 2025-01-25T19:13:33Z Vallenland 2 Защитил страницу [[Заглавная страница]] ([Редактирование=Разрешено только администраторам] (бессрочно) [Переименование=Разрешено только администраторам] (бессрочно)) wikitext text/x-wiki __NOTOC__ <div style="border: solid black; background: rgb(100,100,100); background: radial-gradient(circle, rgba(127,201,255,1) 50%, rgba(82,127,63,1) 100%); color: white; text-align: center;"><big>'''Добро пожаловать на Валленланд Вики, энциклопедию о микрогосударстве Валленланд.'''</big> Валленланд - микрогосударство на части территории города Пскова одноимённой области в России. Оно было основано в 2025 году и активно развивается. </div> <div style="border: solid black; background: rgb(100,100,100); background: radial-gradient(circle, rgba(127,201,255,1) 50%, rgba(82,127,63,1) 100%); color: white; text-align: center; flex: 1; margin: 2px; display: block;">'''Статьи, которые следует прочитать...''' [[Справка:Что такое Валленланд|Простым людям]]ㅤㅤ [[Справка:Как доказать гражданство для вики|Гражданам Валленланда]]ㅤㅤ [[Справка:Установка дипломатических отношений|Главам микронаций]] [[Справка:Как получить гражданство|Желающим получить гражданство Валленланда]]</div> <div style="border: solid black; background: rgb(100,100,100); background: radial-gradient(circle, rgba(127,201,255,1) 50%, rgba(82,127,63,1) 100%); color: white; text-align: center; flex: 1; margin: 2px; display: block;">'''Избранная статья''' Тут ее пока нету но скоро будет </div> 0135b05ca03063d50cf606bc46df5da4cb862321 6 3 2025-01-25T20:02:14Z Vallenland 2 wikitext text/x-wiki __NOTOC__ <div style="border: solid black; background: rgb(100,100,100); background: radial-gradient(circle, rgba(127,201,255,1) 50%, rgba(82,127,63,1) 100%); color: white; text-align: center;">[[Файл:Vallenbox (greeting).png|центр|безрамки|160x160пкс]]<big>'''Добро пожаловать на Валленланд Вики, энциклопедию о микрогосударстве Валленланд.'''</big> Валленланд - микрогосударство на части территории города Пскова одноимённой области в России. Оно было основано в 2025 году и активно развивается. </div> <div style="border: solid black; background: rgb(100,100,100); background: radial-gradient(circle, rgba(127,201,255,1) 50%, rgba(82,127,63,1) 100%); color: white; text-align: center; flex: 1; margin: 2px; display: block;">'''Статьи, которые следует прочитать...''' [[Справка:Что такое Валленланд|Простым людям]]ㅤㅤ [[Справка:Как доказать гражданство для вики|Гражданам Валленланда]]ㅤㅤ [[Справка:Установка дипломатических отношений|Главам микронаций]] [[Справка:Как получить гражданство|Желающим получить гражданство Валленланда]]</div> <div style="border: solid black; background: rgb(100,100,100); background: radial-gradient(circle, rgba(127,201,255,1) 50%, rgba(82,127,63,1) 100%); color: white; text-align: center; flex: 1; margin: 2px; display: block;">'''Избранная статья''' Тут ее пока нету но скоро будет </div> bf55e9be9033796f318da1a5196edb3104182477 Шаблон:Цвет/Композитор.css 10 91 179 2025-01-25T19:46:07Z wikipedia:ru>Putnik 0 упрощение селекторов text text/plain .infobox-above, .infobox-header, .infobox-below { background: #bfe0bf; } @media screen { html.skin-theme-clientpref-night .infobox-above, html.skin-theme-clientpref-night .infobox-header { background: #224422; } html.skin-theme-clientpref-night .infobox-below { background: #182f18; } } @media screen and (prefers-color-scheme: dark) { html.skin-theme-clientpref-os .infobox-above, html.skin-theme-clientpref-os .infobox-header { background: #224422; } html.skin-theme-clientpref-os .infobox-below { background: #182f18; } } /* [[Категория:Шаблоны:Подстраницы CSS]] [[Категория:Шаблоны:Цвета по темам:Музыка|Композитор.css]] */ 174fb6f61c3dc1ef339cd4b496da585e1c4195d6 Файл:Logo.png 6 2 4 2025-01-25T19:56:21Z Vallenland 2 wikitext text/x-wiki x 11f6ad8ec52a2984abaafd7c3b516503785c2072 Файл:Vallenbox (greeting).png 6 3 5 2025-01-25T20:01:43Z Vallenland 2 wikitext text/x-wiki gg f3226f91f77a87d909b8920adc91f9a301a7316b Валленланд 0 4 7 2025-01-25T20:34:38Z Vallenland 2 начало wikitext text/x-wiki '''Валленланд''' (официально '''Валленландская Севастократия''', допускается также написание '''Валенланд''' и '''Валенландская Севастократия''') - микрогосударство на части зелёной территории города Пскова Псковской области. Официально [[Международное признание Валленланда|признан]] макрогосударствами как территория, принадлежащая Российской Федерации. Территории Валленланда расположены к востоку от 4-го многопрофильного лицея города Пскова. Они периодически контролируются то Валленлендом, то Россией. Площадь этих территорий, по измерениям Google Maps, составляет 4060 м<small><sup>2</sup></small> (0,406 га). Непостоянное [[Население Валленланда|население]] Валленланда составляет 1 человека, который и является правителем данного микрогосударства. По национальности он - цыган, следовательно, 100% населения Валленланда составляют цыгане. [[Мандат о независимости Валленланда|Мандатом о независимости]] от [[Национальный день принятия мандата о независимости Валленланда|22 января 2025 года]] установлены также полностью открытые границы и отсутствие государственного контроля за ними. В связи с этим через территорию Валленланда (чаще всего транзитом) проходят несколько десятков человек в день. Главный город, равно как и административно-территориальное устройство, у Валленландской Севастократии отсутствует в связи со слишком маленькой площадью для необходимости этого. Из-за этого Валленланд можно отнести к сверхунитарным микрогосударствам. Валленланд имеет всего лишь одну общую границу с Российской Федерацией длиной в 453 м. Денежной единицы в силу временной нецелесообразности её введения (слишком малое число граждан) Валленланд не имеет. В противном случае денежной единицей станет российский рубль. Валленландская Севастократия долго находилась под властью многих государств - от Киевской Руси до Российской Федерации. Полный перечень всех стран, которые включали её в свой состав: Киевская Русь, Новгородская Республика, Псковская земля (позже - фактически под властью России), Русское государство, Российская империя, Эстония, Российская Советская Федеративная Социалистическая Республика, Великогерманский Рейх, вновь РСФСР и Российская Федерация. Независимый Валленланд появился 22 января 2025 года. Во главе Валленланда стоит севастократор (до этого севастократор был высшим придворным титулом Византии, тем не менее, примерно соответствующим королю), имеющий абсолютную власть в стране до тех пор, пока не будет написана и принята первая конституция Валленланда. На 2025 год этот титул принадлежит Макару Григорьеву. 8415c00debfc340614c6082b870bc7364f0e2f52 MediaWiki:Common.css 8 5 8 2025-01-25T20:37:59Z Vallenland 2 Новая страница: «/* Размещённый здесь CSS будет применяться ко всем темам оформления */ .infobox { background: #eee; border: 1px solid #aaa; float: right; margin: 0 0 1em 1em; padding: 1em; width: 400px; } .infobox-title { font-size: 2em; text-align: center; } .infobox-image { text-align: center; } .infobox-table th { text-align: right; vertical-align: top; width: 120px; } .i...» css text/css /* Размещённый здесь CSS будет применяться ко всем темам оформления */ .infobox { background: #eee; border: 1px solid #aaa; float: right; margin: 0 0 1em 1em; padding: 1em; width: 400px; } .infobox-title { font-size: 2em; text-align: center; } .infobox-image { text-align: center; } .infobox-table th { text-align: right; vertical-align: top; width: 120px; } .infobox-table td { vertical-align: top; } 2bea267ce64b9c1108105f9be0cb220b40436b08 Шаблон:Langi 10 7 12 11 2025-01-25T21:00:05Z Vallenland 2 1 версия импортирована wikitext text/x-wiki <span lang="{{{1}}}" xml:lang="{{{1}}}" style="font-style:italic;">{{{2}}}</span><noinclude>{{doc}}</noinclude> 7bb9f9098c88e770b982402adf30a3bbf645aa4b Модуль:Arguments 828 8 14 13 2025-01-25T21:00:05Z Vallenland 2 1 версия импортирована Scribunto text/plain -- This module provides easy processing of arguments passed to Scribunto from -- #invoke. It is intended for use by other Lua modules, and should not be -- called from #invoke directly. local libraryUtil = require('libraryUtil') local checkType = libraryUtil.checkType local arguments = {} -- Generate four different tidyVal functions, so that we don't have to check the -- options every time we call it. local function tidyValDefault(key, val) if type(val) == 'string' then val = val:match('^%s*(.-)%s*$') if val == '' then return nil else return val end else return val end end local function tidyValTrimOnly(key, val) if type(val) == 'string' then return val:match('^%s*(.-)%s*$') else return val end end local function tidyValRemoveBlanksOnly(key, val) if type(val) == 'string' then if val:find('%S') then return val else return nil end else return val end end local function tidyValNoChange(key, val) return val end local function matchesTitle(given, title) local tp = type( given ) return (tp == 'string' or tp == 'number') and mw.title.new( given ).prefixedText == title end local translate_mt = { __index = function(t, k) return k end } function arguments.getArgs(frame, options) checkType('getArgs', 1, frame, 'table', true) checkType('getArgs', 2, options, 'table', true) frame = frame or {} options = options or {} --[[ -- Set up argument translation. --]] options.translate = options.translate or {} if getmetatable(options.translate) == nil then setmetatable(options.translate, translate_mt) end if options.backtranslate == nil then options.backtranslate = {} for k,v in pairs(options.translate) do options.backtranslate[v] = k end end if options.backtranslate and getmetatable(options.backtranslate) == nil then setmetatable(options.backtranslate, { __index = function(t, k) if options.translate[k] ~= k then return nil else return k end end }) end --[[ -- Get the argument tables. If we were passed a valid frame object, get the -- frame arguments (fargs) and the parent frame arguments (pargs), depending -- on the options set and on the parent frame's availability. If we weren't -- passed a valid frame object, we are being called from another Lua module -- or from the debug console, so assume that we were passed a table of args -- directly, and assign it to a new variable (luaArgs). --]] local fargs, pargs, luaArgs if type(frame.args) == 'table' and type(frame.getParent) == 'function' then if options.wrappers then --[[ -- The wrappers option makes Module:Arguments look up arguments in -- either the frame argument table or the parent argument table, but -- not both. This means that users can use either the #invoke syntax -- or a wrapper template without the loss of performance associated -- with looking arguments up in both the frame and the parent frame. -- Module:Arguments will look up arguments in the parent frame -- if it finds the parent frame's title in options.wrapper; -- otherwise it will look up arguments in the frame object passed -- to getArgs. --]] local parent = frame:getParent() if not parent then fargs = frame.args else local title = parent:getTitle():gsub('/песочница$', '') local found = false if matchesTitle(options.wrappers, title) then found = true elseif type(options.wrappers) == 'table' then for _,v in pairs(options.wrappers) do if matchesTitle(v, title) then found = true break end end end -- We test for false specifically here so that nil (the default) acts like true. if found or options.frameOnly == false then pargs = parent.args end if not found or options.parentOnly == false then fargs = frame.args end end else -- options.wrapper isn't set, so check the other options. if not options.parentOnly then fargs = frame.args end if not options.frameOnly then local parent = frame:getParent() pargs = parent and parent.args or nil end end if options.parentFirst then fargs, pargs = pargs, fargs end else luaArgs = frame end -- Set the order of precedence of the argument tables. If the variables are -- nil, nothing will be added to the table, which is how we avoid clashes -- between the frame/parent args and the Lua args. local argTables = {fargs} argTables[#argTables + 1] = pargs argTables[#argTables + 1] = luaArgs --[[ -- Generate the tidyVal function. If it has been specified by the user, we -- use that; if not, we choose one of four functions depending on the -- options chosen. This is so that we don't have to call the options table -- every time the function is called. --]] local tidyVal = options.valueFunc if tidyVal then if type(tidyVal) ~= 'function' then error( "bad value assigned to option 'valueFunc'" .. '(function expected, got ' .. type(tidyVal) .. ')', 2 ) end elseif options.trim ~= false then if options.removeBlanks ~= false then tidyVal = tidyValDefault else tidyVal = tidyValTrimOnly end else if options.removeBlanks ~= false then tidyVal = tidyValRemoveBlanksOnly else tidyVal = tidyValNoChange end end --[[ -- Set up the args, metaArgs and nilArgs tables. args will be the one -- accessed from functions, and metaArgs will hold the actual arguments. Nil -- arguments are memoized in nilArgs, and the metatable connects all of them -- together. --]] local args, metaArgs, nilArgs, metatable = {}, {}, {}, {} setmetatable(args, metatable) local function mergeArgs(tables) --[[ -- Accepts multiple tables as input and merges their keys and values -- into one table. If a value is already present it is not overwritten; -- tables listed earlier have precedence. We are also memoizing nil -- values, which can be overwritten if they are 's' (soft). --]] for _, t in ipairs(tables) do for key, val in pairs(t) do if metaArgs[key] == nil and nilArgs[key] ~= 'h' then local tidiedVal = tidyVal(key, val) if tidiedVal == nil then nilArgs[key] = 's' else metaArgs[key] = tidiedVal end end end end end --[[ -- Define metatable behaviour. Arguments are memoized in the metaArgs table, -- and are only fetched from the argument tables once. Fetching arguments -- from the argument tables is the most resource-intensive step in this -- module, so we try and avoid it where possible. For this reason, nil -- arguments are also memoized, in the nilArgs table. Also, we keep a record -- in the metatable of when pairs and ipairs have been called, so we do not -- run pairs and ipairs on the argument tables more than once. We also do -- not run ipairs on fargs and pargs if pairs has already been run, as all -- the arguments will already have been copied over. --]] metatable.__index = function (t, key) --[[ -- Fetches an argument when the args table is indexed. First we check -- to see if the value is memoized, and if not we try and fetch it from -- the argument tables. When we check memoization, we need to check -- metaArgs before nilArgs, as both can be non-nil at the same time. -- If the argument is not present in metaArgs, we also check whether -- pairs has been run yet. If pairs has already been run, we return nil. -- This is because all the arguments will have already been copied into -- metaArgs by the mergeArgs function, meaning that any other arguments -- must be nil. --]] if type(key) == 'string' then key = options.translate[key] end local val = metaArgs[key] if val ~= nil then return val elseif metatable.donePairs or nilArgs[key] then return nil end for _, argTable in ipairs(argTables) do local argTableVal = tidyVal(key, argTable[key]) if argTableVal ~= nil then metaArgs[key] = argTableVal return argTableVal end end nilArgs[key] = 'h' return nil end metatable.__newindex = function (t, key, val) -- This function is called when a module tries to add a new value to the -- args table, or tries to change an existing value. if type(key) == 'string' then key = options.translate[key] end if options.readOnly then error( 'could not write to argument table key "' .. tostring(key) .. '"; the table is read-only', 2 ) elseif options.noOverwrite and args[key] ~= nil then error( 'could not write to argument table key "' .. tostring(key) .. '"; overwriting existing arguments is not permitted', 2 ) elseif val == nil then --[[ -- If the argument is to be overwritten with nil, we need to erase -- the value in metaArgs, so that __index, __pairs and __ipairs do -- not use a previous existing value, if present; and we also need -- to memoize the nil in nilArgs, so that the value isn't looked -- up in the argument tables if it is accessed again. --]] metaArgs[key] = nil nilArgs[key] = 'h' else metaArgs[key] = val end end local function translatenext(invariant) local k, v = next(invariant.t, invariant.k) invariant.k = k if k == nil then return nil elseif type(k) ~= 'string' or not options.backtranslate then return k, v else local backtranslate = options.backtranslate[k] if backtranslate == nil then -- Skip this one. This is a tail call, so this won't cause stack overflow return translatenext(invariant) else return backtranslate, v end end end metatable.__pairs = function () -- Called when pairs is run on the args table. if not metatable.donePairs then mergeArgs(argTables) metatable.donePairs = true end return translatenext, { t = metaArgs } end local function inext(t, i) -- This uses our __index metamethod local v = t[i + 1] if v ~= nil then return i + 1, v end end metatable.__ipairs = function (t) -- Called when ipairs is run on the args table. return inext, t, 0 end return args end return arguments e6be8dfccffa2057c3d50700f350d8d140c1dbf9 Модуль:Check for unknown parameters 828 9 16 15 2025-01-25T21:00:06Z Vallenland 2 1 версия импортирована Scribunto text/plain -- This module may be used to compare the arguments passed to the parent -- with a list of arguments, returning a specified result if an argument is -- not on the list local p = {} local function trim(s) return s:match('^%s*(.-)%s*$') end local function isnotempty(s) return s and trim(s) ~= '' end function p.check (frame) local args = frame.args local pargs = frame:getParent().args local ignoreblank = isnotempty(frame.args['ignoreblank']) local showblankpos = isnotempty(frame.args['showblankpositional']) local knownargs = {} local unknown = frame.args['unknown'] or 'Found _VALUE_, ' local preview = frame.args['preview'] local values = {} local res = {} local regexps = {} -- create the list of known args, regular expressions, and the return string for k, v in pairs(args) do if type(k) == 'number' then v = trim(v) knownargs[v] = 1 elseif k:find('^regexp[1-9][0-9]*$') then table.insert(regexps, '^' .. v .. '$') end end if isnotempty(preview) then preview = '<div class="hatnote" style="color: var(--color-error, #d73333)"><strong>Предупреждение:</strong> ' .. preview .. ' (это сообщение видно только при предпросмотре страницы).</div>' elseif preview == nil then preview = unknown end -- loop over the parent args, and make sure they are on the list for k, v in pairs(pargs) do if type(k) == 'string' and knownargs[k] == nil then local knownflag = false for i, regexp in ipairs(regexps) do if mw.ustring.match(k, regexp) then knownflag = true break end end if not knownflag and ( not ignoreblank or isnotempty(v) ) then k = mw.ustring.gsub(k, '[^%w\-_ ]', '?') table.insert(values, k) end elseif type(k) == 'number' and knownargs[tostring(k)] == nil and ( showblankpos or isnotempty(v) ) then local vlen = mw.ustring.len(v) v = mw.ustring.sub(v, 1, (vlen < 25) and vlen or 25) v = mw.ustring.gsub(v, '[^%w\-_ ]', '?') table.insert(values, k .. ' = ' .. v .. ((vlen >= 25) and ' ...' or '')) end end -- add resuls to the output tables if #values > 0 then if frame:preprocess( "{{REVISIONID}}" ) == "" then unknown = preview end for k, v in pairs(values) do if v == '' then -- Fix odd bug for | = which gets stripped to the empty string and -- breaks category links v = ' ' end local r = unknown:gsub('_VALUE_', v) table.insert(res, r) end end return table.concat(res) end function p.generate (frame) local res = '{{#invoke:check for unknown parameters|check\n' .. '|unknown=' .. frame.args['unknown'] .. '\n' local checkerparams = {'ignoreblank', 'preview', 'showblankpositional'} for _, v in pairs(checkerparams) do if frame.args[v] then res = res .. '|' .. v .. '=' .. frame.args[v] .. '\n' end end local templatenamespace = frame.args[1] local templatetitle = frame.args[2] local pagepointer = mw.title.new(templatetitle, templatenamespace) -- именно такой порядок! local text = pagepointer.getContent(pagepointer) local params = {} for param in string.gmatch(text, '\{\{\{([^\|\}]*)') do params[#params+1] = mw.text.trim(param) end table.sort(params) for k, v in pairs(params) do if k == 1 or v ~= params[k-1] then res = res .. '|' .. v end end res = res .. '}}' return res end return p 9da4c0ae23797bb024279d7544e897ae3f2bbf43 Модуль:TableTools 828 10 18 17 2025-01-25T21:00:06Z Vallenland 2 1 версия импортирована Scribunto text/plain --[[ ------------------------------------------------------------------------------------ -- TableTools -- -- -- -- This module includes a number of functions for dealing with Lua tables. -- -- It is a meta-module, meant to be called from other Lua modules, and should -- -- not be called directly from #invoke. -- ------------------------------------------------------------------------------------ --]] local libraryUtil = require('libraryUtil') local p = {} -- Define often-used variables and functions. local floor = math.floor local infinity = math.huge local checkType = libraryUtil.checkType local checkTypeMulti = libraryUtil.checkTypeMulti --[[ ------------------------------------------------------------------------------------ -- isPositiveInteger -- -- This function returns true if the given value is a positive integer, and false -- if not. Although it doesn't operate on tables, it is included here as it is -- useful for determining whether a given table key is in the array part or the -- hash part of a table. ------------------------------------------------------------------------------------ --]] function p.isPositiveInteger(v) if type(v) == 'number' and v >= 1 and floor(v) == v and v < infinity then return true else return false end end --[[ ------------------------------------------------------------------------------------ -- isNan -- -- This function returns true if the given number is a NaN value, and false -- if not. Although it doesn't operate on tables, it is included here as it is -- useful for determining whether a value can be a valid table key. Lua will -- generate an error if a NaN is used as a table key. ------------------------------------------------------------------------------------ --]] function p.isNan(v) if type(v) == 'number' and tostring(v) == '-nan' then return true else return false end end --[[ ------------------------------------------------------------------------------------ -- shallowClone -- -- This returns a clone of a table. The value returned is a new table, but all -- subtables and functions are shared. Metamethods are respected, but the returned -- table will have no metatable of its own. ------------------------------------------------------------------------------------ --]] function p.shallowClone(t) local ret = {} for k, v in pairs(t) do ret[k] = v end return ret end --[[ ------------------------------------------------------------------------------------ -- removeDuplicates -- -- This removes duplicate values from an array. Non-positive-integer keys are -- ignored. The earliest value is kept, and all subsequent duplicate values are -- removed, but otherwise the array order is unchanged. ------------------------------------------------------------------------------------ --]] function p.removeDuplicates(t) checkType('removeDuplicates', 1, t, 'table') local isNan = p.isNan local ret, exists = {}, {} for i, v in ipairs(t) do if isNan(v) then -- NaNs can't be table keys, and they are also unique, so we don't need to check existence. ret[#ret + 1] = v else if not exists[v] then ret[#ret + 1] = v exists[v] = true end end end return ret end --[[ ------------------------------------------------------------------------------------ -- numKeys -- -- This takes a table and returns an array containing the numbers of any numerical -- keys that have non-nil values, sorted in numerical order. ------------------------------------------------------------------------------------ --]] function p.numKeys(t) checkType('numKeys', 1, t, 'table') local isPositiveInteger = p.isPositiveInteger local nums = {} for k, v in pairs(t) do if isPositiveInteger(k) then nums[#nums + 1] = k end end table.sort(nums) return nums end --[[ ------------------------------------------------------------------------------------ -- affixNums -- -- This takes a table and returns an array containing the numbers of keys with the -- specified prefix and suffix. For example, for the table -- {a1 = 'foo', a3 = 'bar', a6 = 'baz'} and the prefix "a", affixNums will -- return {1, 3, 6}. ------------------------------------------------------------------------------------ --]] function p.affixNums(t, prefix, suffix) checkType('affixNums', 1, t, 'table') checkType('affixNums', 2, prefix, 'string', true) checkType('affixNums', 3, suffix, 'string', true) local function cleanPattern(s) -- Cleans a pattern so that the magic characters ()%.[]*+-?^$ are interpreted literally. s = s:gsub('([%(%)%%%.%[%]%*%+%-%?%^%$])', '%%%1') return s end prefix = prefix or '' suffix = suffix or '' prefix = cleanPattern(prefix) suffix = cleanPattern(suffix) local pattern = '^' .. prefix .. '([1-9]%d*)' .. suffix .. '$' local nums = {} for k, v in pairs(t) do if type(k) == 'string' then local num = mw.ustring.match(k, pattern) if num then nums[#nums + 1] = tonumber(num) end end end table.sort(nums) return nums end --[[ ------------------------------------------------------------------------------------ -- numData -- -- Given a table with keys like ("foo1", "bar1", "foo2", "baz2"), returns a table -- of subtables in the format -- { [1] = {foo = 'text', bar = 'text'}, [2] = {foo = 'text', baz = 'text'} } -- Keys that don't end with an integer are stored in a subtable named "other". -- The compress option compresses the table so that it can be iterated over with -- ipairs. ------------------------------------------------------------------------------------ --]] function p.numData(t, compress) checkType('numData', 1, t, 'table') checkType('numData', 2, compress, 'boolean', true) local ret = {} for k, v in pairs(t) do local prefix, num = mw.ustring.match(tostring(k), '^([^0-9]*)([1-9][0-9]*)$') if num then num = tonumber(num) local subtable = ret[num] or {} if prefix == '' then -- Positional parameters match the blank string; put them at the start of the subtable instead. prefix = 1 end subtable[prefix] = v ret[num] = subtable else local subtable = ret.other or {} subtable[k] = v ret.other = subtable end end if compress then local other = ret.other ret = p.compressSparseArray(ret) ret.other = other end return ret end --[[ ------------------------------------------------------------------------------------ -- compressSparseArray -- -- This takes an array with one or more nil values, and removes the nil values -- while preserving the order, so that the array can be safely traversed with -- ipairs. ------------------------------------------------------------------------------------ --]] function p.compressSparseArray(t) checkType('compressSparseArray', 1, t, 'table') local ret = {} local nums = p.numKeys(t) for _, num in ipairs(nums) do ret[#ret + 1] = t[num] end return ret end --[[ ------------------------------------------------------------------------------------ -- sparseIpairs -- -- This is an iterator for sparse arrays. It can be used like ipairs, but can -- handle nil values. ------------------------------------------------------------------------------------ --]] function p.sparseIpairs(t) checkType('sparseIpairs', 1, t, 'table') local nums = p.numKeys(t) local i = 0 local lim = #nums return function () i = i + 1 if i <= lim then local key = nums[i] return key, t[key] else return nil, nil end end end --[[ ------------------------------------------------------------------------------------ -- size -- -- This returns the size of a key/value pair table. It will also work on arrays, -- but for arrays it is more efficient to use the # operator. ------------------------------------------------------------------------------------ --]] function p.size(t) checkType('size', 1, t, 'table') local i = 0 for k in pairs(t) do i = i + 1 end return i end local function defaultKeySort(item1, item2) -- "number" < "string", so numbers will be sorted before strings. local type1, type2 = type(item1), type(item2) if type1 ~= type2 then return type1 < type2 else -- This will fail with table, boolean, function. return item1 < item2 end end --[[ Returns a list of the keys in a table, sorted using either a default comparison function or a custom keySort function. ]] function p.keysToList(t, keySort, checked) if not checked then checkType('keysToList', 1, t, 'table') checkTypeMulti('keysToList', 2, keySort, { 'function', 'boolean', 'nil' }) end local list = {} local index = 1 for key, value in pairs(t) do list[index] = key index = index + 1 end if keySort ~= false then keySort = type(keySort) == 'function' and keySort or defaultKeySort table.sort(list, keySort) end return list end --[[ Iterates through a table, with the keys sorted using the keysToList function. If there are only numerical keys, sparseIpairs is probably more efficient. ]] function p.sortedPairs(t, keySort) checkType('sortedPairs', 1, t, 'table') checkType('sortedPairs', 2, keySort, 'function', true) local list = p.keysToList(t, keySort, true) local i = 0 return function() i = i + 1 local key = list[i] if key ~= nil then return key, t[key] else return nil, nil end end end --[[ Returns true if all keys in the table are consecutive integers starting at 1. --]] function p.isArray(t) checkType("isArray", 1, t, "table") local i = 0 for k, v in pairs(t) do i = i + 1 if t[i] == nil then return false end end return true end -- { "a", "b", "c" } -> { a = 1, b = 2, c = 3 } function p.invert(array) checkType("invert", 1, array, "table") local map = {} for i, v in ipairs(array) do map[v] = i end return map end --[[ { "a", "b", "c" } -> { ["a"] = true, ["b"] = true, ["c"] = true } --]] function p.listToSet(t) checkType("listToSet", 1, t, "table") local set = {} for _, item in ipairs(t) do set[item] = true end return set end --[[ Recursive deep copy function. Preserves identities of subtables. ]] local function _deepCopy(orig, includeMetatable, already_seen) -- Stores copies of tables indexed by the original table. already_seen = already_seen or {} local copy = already_seen[orig] if copy ~= nil then return copy end if type(orig) == 'table' then copy = {} for orig_key, orig_value in pairs(orig) do copy[deepcopy(orig_key, includeMetatable, already_seen)] = deepcopy(orig_value, includeMetatable, already_seen) end already_seen[orig] = copy if includeMetatable then local mt = getmetatable(orig) if mt ~= nil then local mt_copy = deepcopy(mt, includeMetatable, already_seen) setmetatable(copy, mt_copy) already_seen[mt] = mt_copy end end else -- number, string, boolean, etc copy = orig end return copy end function p.deepCopy(orig, noMetatable, already_seen) checkType("deepCopy", 3, already_seen, "table", true) return _deepCopy(orig, not noMetatable, already_seen) end --[[ Concatenates all values in the table that are indexed by a number, in order. sparseConcat{ a, nil, c, d } => "acd" sparseConcat{ nil, b, c, d } => "bcd" ]] function p.sparseConcat(t, sep, i, j) local list = {} local list_i = 0 for _, v in p.sparseIpairs(t) do list_i = list_i + 1 list[list_i] = v end return table.concat(list, sep, i, j) end --[[ -- This returns the length of a table, or the first integer key n counting from -- 1 such that t[n + 1] is nil. It is similar to the operator #, but may return -- a different value when there are gaps in the array portion of the table. -- Intended to be used on data loaded with mw.loadData. For other tables, use #. -- Note: #frame.args in frame object always be set to 0, regardless of -- the number of unnamed template parameters, so use this function for -- frame.args. --]] function p.length(t) local i = 1 while t[i] ~= nil do i = i + 1 end return i - 1 end function p.inArray(arr, valueToFind) checkType("inArray", 1, arr, "table") -- if valueToFind is nil, error? for _, v in ipairs(arr) do if v == valueToFind then return true end end return false end return p fe918509f168332267834b3a6f5c219a9de5b2e7 Модуль:Template call code 828 11 20 19 2025-01-25T21:00:07Z Vallenland 2 1 версия импортирована Scribunto text/plain local getArgs = require('Module:Arguments').getArgs local ru = mw.language.new('ru') local p = {} -- Используется для того, чтобы можно было удалять элементы из таблицы local function copy(other) local res = {} for k, v in pairs(other) do res[k] = v end return res end local function makeInvokeFunc(funcName, flags) return function (frame) local args = copy(getArgs(frame, { trim = false, removeBlanks = false })) return p[funcName](args, flags) end end --предотвращает обработку вики-текста в отображении образца local function processText(str, nowiki) local res = str if nowiki then str = mw.text.unstripNoWiki(str) str = string.gsub(str, '%[', '&#91;') str = string.gsub(str, '%]', '&#93;') str = string.gsub(str, '<', '&lt;') str = string.gsub(str, '>', '&gt;') str = string.gsub(str, '{', '&#123;') str = string.gsub(str, '|', '&#124;') str = string.gsub(str, '}', '&#125;') str = string.gsub(str, '\'', '&#39;') str = string.gsub(str, '"', '&quot;') str = string.gsub(str, '(://)', '<span>%1</span>') end return str end local function addParams(args, params) local text, equals_pos, param, value = '', 0, '', '' local function addPipe() if params.spaced then text = text .. ' ' end text = text .. '<span class="' if not params.spaced then text = text .. ' ts-templateCallCode-pipe' end if not params.black then text = text .. ' ts-templateCallCode-weak' end -- &#124;, чтобы не трактовалось как разделитель ячеек в таблицах text = text .. '">&#124;</span>' end local beforeParam = '<span class="ts-templateCallCode-param">' local afterParam = '</span>' for k, v in pairs(args) do if type(k) == 'number' then -- Неименованные параметры if k >= params.from then equals_pos = v:find('=') if equals_pos and v:find('{{=}}') == equals_pos - 2 then equals_pos = nil end if equals_pos then -- Содержащие «=» преобразуем в именованные param = v:sub(1, equals_pos - 1) value = v:sub(equals_pos + 1) addPipe() text = text .. beforeParam .. processText(param, params.nowiki) .. '=' .. processText(value, params.nowiki) .. afterParam else -- Истинно неименованные addPipe() local paramValue = processText(v, params.nowiki) if #paramValue ~= 0 then text = text .. beforeParam .. paramValue .. afterParam end end end elseif not k:find('^_') then -- Именованные параметры, исключая модификаторы внешнего вида addPipe() text = text .. beforeParam .. processText(k, params.nowiki) .. '=' .. processText(v, params.nowiki) .. afterParam end end return text end function p._main(args, flags) local name = args[1] table.remove(args, 1) -- Вещи типа «=» в первом параметре if not name then for k, v in pairs(args) do if not k:find('^_') then name = k .. '=' .. v args[k] = nil break end end end local optpText if not flags.withoutParams then if name then local spanOffset = mw.ustring.find(name, '<span') -- След использования шаблона optp if spanOffset then optpText = mw.ustring.sub(name, spanOffset) name = mw.ustring.sub(name, 1, spanOffset - 1) end end end local yesno = require('Module:Yesno') local nolink, subst, podst, global, nav, noRedirect, ucFirst, black, nobr local tag, style, comment, lang, sister, global, textInPlaceOfName, namePrefix, prefix, postfix, nowiki local spaced, from if flags.withoutParams then for i, v in ipairs(args) do if v == 'nl' or v == 'nolink' then noLink = true elseif v == 's' then subst = true elseif v == 'п' then podst = true elseif v == 'g' then global = true elseif v == 'nav' then nav = true elseif v == 'noredir' then noRedirect = true elseif v == 'u' then ucFirst = true elseif v == 'b' then black = true elseif v == 'nobr' then nobr = true end end tag = args.tag or 'span' style = args.style comment = args.comment lang = args.lang sister = args.sister textInPlaceOfName = args.text namePrefix = args.nameprefix prefix = args.prefix postfix = args.postfix nowiki = args.nowiki else noLink = yesno(args._nolink or args._nl, false) or not yesno(args._link, false) subst = yesno(args._s, false) podst = yesno(args['_п'], false) global = yesno(args._g, false) nav = yesno(args._nav, false) noRedirect = yesno(args._noredir, false) ucFirst = yesno(args._u, false) black = yesno(args._b, false) nobr = yesno(args._nobr, false) tag = args._tag or 'span' style = args._style comment = args._comment lang = args._lang sister = args._sister textInPlaceOfName = args._text namePrefix = args._nameprefix prefix = args._prefix postfix = args._postfix nowiki = args._nowiki spaced = yesno(args._spaced, false) from = (tonumber(args._from) or 2) - 1 end global = global or name and mw.ustring.sub(name, 1, 1) == ':' black = black or tag ~= 'span' if textInPlaceOfName == '' then textInPlaceOfName = nil end if comment == '' then comment = nil end if lang == '' then lang = nil end if sister == '' then sister = nil end if namePrefix == '' then namePrefix = nil end if name then local trimmedName = mw.text.trim(name) if ru:lc(mw.ustring.sub(trimmedName, 1, 6)) == 'subst:' then subst = true name = mw.ustring.sub(trimmedName, 7) end if ru:lc(mw.ustring.sub(trimmedName, 1, 6)) == 'подст:' then podst = true name = mw.ustring.sub(trimmedName, 7) end end if subst then namePrefix = 'subst:' elseif podst then namePrefix = 'подст:' end local currentTitle = mw.title.getCurrentTitle() -- При опущенном первом параметре берём имя шаблона из названия страницы if name == '' or not name then local currentTitleRoot = currentTitle.rootText if not ucFirst and ( ( ru:uc(currentTitleRoot) ~= currentTitleRoot and -- Книга:Литературное наследство, TranslateDate not mw.ustring.match(currentTitleRoot, '^[А-Яа-яA-Za-z]+:?[А-ЯA-Z]') ) or #currentTitleRoot == 1 ) then name = ru:lcfirst(currentTitleRoot) else name = currentTitleRoot end end -- Начинаем собирать код local linkBody, titleObject, linkBegin, linkDivider, linkEnd local prefixes = {} if lang then table.insert(prefixes, lang) end if sister then table.insert(prefixes, sister) end linkBody = table.concat(prefixes, ':') if #linkBody ~= 0 then linkBody = ':' .. linkBody end if mw.ustring.sub(name, 1, 1) ~= ':' then linkBody = linkBody .. ':' end if not global then linkBody = linkBody .. 'Template:' end linkBody = linkBody .. name titleObject = mw.title.new(linkBody) local noLink = noLink or currentTitle == titleObject if not noLink then if not noRedirect or ( noRedirect and not lang and not sister and not titleObject.exists ) then linkBegin = '[[' linkEnd = ']]' linkDivider = '|' else linkBegin = '[' linkEnd = ']' linkDivider = ' ' linkBody = titleObject:fullUrl('redirect=no') end end local text = '' if tag then text = text .. '<' .. tag .. ' class="ts-templateCallCode' if nobr then text = text .. ' nowrap' end text = text .. '"' if style then text = text .. ' style="' .. style .. '"' end text = text .. '>' end if prefix then text = text .. processText(prefix, nowiki) end text = text .. '<span class="' if not spaced then text = text .. ' ts-templateCallCode-opening' end if not black then text = text .. ' ts-templateCallCode-weak' end text = text .. '">{{' if namePrefix then text = text .. namePrefix end text = text .. '</span>' if nav and currentTitle == titleObject then text = text .. '\'\'\'' end text = text .. '<span class="ts-templateCallCode-templateName" data-navboxnavigation-link="0">' local commentedLabel if comment then -- https://phabricator.wikimedia.org/T200704 -- commentedLabel = mw.getCurrentFrame():expandTemplate({title = 'comment', args = {(textInPlaceOfName or name), comment}}) commentedLabel = '<span class="commentedText" title="' .. comment .. '" style="border-bottom: 1px dotted; cursor: help;">' .. (textInPlaceOfName or name) .. '</span>' end local label = (commentedLabel or textInPlaceOfName or name) if not noLink then if noRedirect then text = text .. '<span class="plainlinks">' end text = text .. linkBegin .. linkBody .. linkDivider .. label .. linkEnd if noRedirect then text = text .. '</span>' end else text = text .. label end text = text .. '</span>' if nav and currentTitle == titleObject then text = text .. '\'\'\'' end if not flags.withoutParams then if optpText then text = text .. optpText end text = text .. addParams(args, { spaced = spaced, black = black, nowiki = nowiki, from = from }) if spaced then text = text .. ' ' end end text = text .. '<span class="' if not spaced then text = text .. ' ts-templateCallCode-closing' end if not black then text = text .. ' ts-templateCallCode-weak' end text = text .. '">}}</span>' if postfix then text = text .. processText(postfix, nowiki) end if tag then text = text .. '</' .. tag .. '>' end local ts = mw.getCurrentFrame():extensionTag{ name = 'templatestyles', args = { src = 'Модуль:Template call code/styles.css' } } return ts .. text end function p._onlyParams(args) local yesno = require('Module:Yesno') return addParams(args, { spaced = yesno(args._spaced, false), black = true, nowiki = yesno(args._nowiki, false), from = 1 }) end p.withoutParams = makeInvokeFunc('_main', {withoutParams = true}) p.withParams = makeInvokeFunc('_main', {withoutParams = false}) p.onlyParams = makeInvokeFunc('_onlyParams') return p c4cde66869b509219e9bf629a766ce30ad0bdf97 Модуль:Yesno 828 12 22 21 2025-01-25T21:00:07Z Vallenland 2 1 версия импортирована Scribunto text/plain -- Function allowing for consistent treatment of boolean-like wikitext input. -- It works similarly to the template {{yesno}}. return function (val, default) -- If your wiki uses non-ascii characters for any of "yes", "no", etc., you -- should replace "val:lower()" with "mw.ustring.lower(val)" in the -- following line. val = type(val) == 'string' and val:lower() or val if val == nil then return nil elseif val == true or val == 'yes' or val == 'y' or val == 'true' or val == 't' or val == 'да' or val == 'д' -- кириллица or val == 'у' or val == '+' or tonumber(val) == 1 then return true elseif val == false or val == 'no' or val == 'n' or val == 'false' or val == 'f' or val == 'нет' or val == 'н' or val == '-' or tonumber(val) == 0 then return false else return default end end ae94e12a838e770797317ed07b57b330ffeb7658 Модуль:Template call code/styles.css 828 13 24 23 2025-01-25T21:00:08Z Vallenland 2 1 версия импортирована text text/plain .ts-templateCallCode-weak { color: #72777d; } .ts-templateCallCode-pipe { margin: 0 2px; } .ts-templateCallCode-pipe + .ts-templateCallCode-pipe, /* Template:Optp */ .ts-templateCallCode-pipe + .ts-templateCallCode-param > .ts-templateCallCode-weak:first-child > .ts-templateCallCode-pipe:first-child { margin-left: 0; } .ts-templateCallCode-param + .ts-templateCallCode-closing { margin-left: 2px; } span.ts-templateCallCode > .ts-templateCallCode-templateName a { /* Решение из https://ru.wikipedia.org/wiki/Шаблон:Фиттс */ padding: 0 0.5em !important; /* Перезаписываем стиль для .plainlinks a.external */ position: relative; margin: -0.5em; } /* [[Категория:Шаблоны:Подстраницы CSS]] */ b3ed166240cf28c48a58b8d992794b753b2c6ef5 Модуль:Message box 828 14 26 25 2025-01-25T21:00:08Z Vallenland 2 1 версия импортирована Scribunto text/plain -- This is a meta-module for producing message box templates, including -- {{mbox}}, {{ambox}}, {{imbox}}, {{tmbox}}, {{ombox}}, {{cmbox}} and {{fmbox}}. -- Load necessary modules. require('strict') local getArgs local categoryHandler = require('Module:Category handler')._main local yesno = require('Module:Yesno') local boxDate = require('Module:Calendar').bxDate; -- Get a language object for formatDate and ucfirst. local lang = mw.language.getContentLanguage() -- Define constants local CONFIG_MODULE = 'Module:Message box/configuration' -------------------------------------------------------------------------------- -- Helper functions -------------------------------------------------------------------------------- local function getTitleObject(...) -- Get the title object, passing the function through pcall -- in case we are over the expensive function count limit. local success, title = pcall(mw.title.new, ...) if success then return title end end local function union(t1, t2) -- Returns the union of two arrays. local vals = {} for i, v in ipairs(t1) do vals[v] = true end for i, v in ipairs(t2) do vals[v] = true end local ret = {} for k in pairs(vals) do table.insert(ret, k) end table.sort(ret) return ret end local function getArgNums(args, prefix) local nums = {} for k, v in pairs(args) do local num = mw.ustring.match(tostring(k), '^' .. prefix .. '([1-9]%d*)$') if num then table.insert(nums, tonumber(num)) end end table.sort(nums) return nums end -- локальная обёртка, игнорирует таблицу с номерами дня, месяца и года local function formatDate(txtDateIn, strFormat, params) local txtDateOut, date, status = boxDate(txtDateIn, strFormat, params) if status.brk then return error(status.errorText) else return txtDateOut end end -------------------------------------------------------------------------------- -- Box class definition -------------------------------------------------------------------------------- local MessageBox = {} MessageBox.__index = MessageBox function MessageBox.new(boxType, args, cfg) args = args or {} local obj = {} -- Set the title object and the namespace. obj.title = getTitleObject(args.page) or mw.title.getCurrentTitle() -- Set the config for our box type. obj.cfg = cfg[boxType] if not obj.cfg then local ns = obj.title.namespace -- boxType is "mbox" or invalid input if ns == 0 then obj.cfg = cfg.ambox -- main namespace elseif ns == 6 then obj.cfg = cfg.imbox -- file namespace elseif ns == 14 then obj.cfg = cfg.cmbox -- category namespace else local nsTable = mw.site.namespaces[ns] if nsTable and nsTable.isTalk then obj.cfg = cfg.tmbox -- any talk namespace else obj.cfg = cfg.ombox -- other namespaces or invalid input end end end -- Set the arguments, and remove all blank arguments except for the ones -- listed in cfg.allowBlankParams. do local newArgs = {} for k, v in pairs(args) do if v ~= '' then newArgs[k] = v end end for i, param in ipairs(obj.cfg.allowBlankParams or {}) do newArgs[param] = args[param] end obj.args = newArgs end -- Define internal data structure. obj.categories = {} obj.classes = {} return setmetatable(obj, MessageBox) end function MessageBox:addCat(ns, cat, sort) if not cat then return nil end if sort then cat = string.format('[[Категория:%s|%s]]', cat, sort) else cat = string.format('[[Категория:%s]]', cat) end self.categories[ns] = self.categories[ns] or {} table.insert(self.categories[ns], cat) end function MessageBox:addClass(class) if not class then return nil end table.insert(self.classes, class) end function MessageBox:setParameters() local args = self.args local cfg = self.cfg -- Get type data. self.type = args.type local typeData = cfg.types[self.type] self.invalidTypeError = cfg.showInvalidTypeError and self.type and not typeData typeData = typeData or cfg.types[cfg.default] self.typeClass = typeData.class self.typeImage = typeData.image -- Find if the box has been wrongly substituted. self.isSubstituted = cfg.substCheck and args.subst == 'SUBST' -- Find whether we are using a small message box. self.isSmall = cfg.allowSmall and ( cfg.smallParam and args.small == cfg.smallParam or not cfg.smallParam and yesno(args.small) ) -- Add attributes, classes and styles. self.id = args.id self.name = args.name if self.name then self:addClass('mbox-' .. string.gsub(self.name,' ','_')) end if yesno(args.plainlinks) ~= false then self:addClass('plainlinks') end for _, class in ipairs(cfg.classes or {}) do self:addClass(class) end if self.isSmall then self:addClass(cfg.smallClass or 'mbox-small') end self:addClass(self.typeClass) self:addClass(args.class) self.style = args.style self.attrs = args.attrs self.dataLabel1 = args['data-label-1'] self.dataLabel2 = args['data-label-2'] self.dataLabel3 = args['data-label-3'] self.dataValue1 = args['data-value-1'] self.dataValue2 = args['data-value-2'] self.dataValue3 = args['data-value-3'] -- Set text style. self.textstyle = args.textstyle -- Find if we are on the template page or not. This functionality is only -- used if useCollapsibleTextFields is set, or if both cfg.templateCategory -- and cfg.templateCategoryRequireName are set. self.useCollapsibleTextFields = cfg.useCollapsibleTextFields if self.useCollapsibleTextFields or cfg.templateCategory and cfg.templateCategoryRequireName then self.name = args.name if self.name then local templateName = mw.ustring.match( self.name, '^[tT][eE][mM][pP][lL][aA][tT][eE][%s_]*:[%s_]*(.*)$' ) or self.name templateName = ('Template:' .. templateName) or ('Шаблон:' .. templateName) self.templateTitle = getTitleObject(templateName) end self.isTemplatePage = self.templateTitle and mw.title.equals(self.title, self.templateTitle) end -- Process data for collapsible text fields. At the moment these are only -- used in {{ambox}}. if self.useCollapsibleTextFields then -- Get the self.issue value. if self.isSmall and args.smalltext then self.issue = args.smalltext else if args.sect and args.sect ~= '' or nil then local issue_sect = args.issue_sect issue_sect = type(issue_sect) == 'string' and issue_sect ~= '' and issue_sect or nil local text_sect = args.text_sect text_sect = type(text_sect) == 'string' and text_sect ~= '' and text_sect or nil local issues = {} table.insert(issues, issue_sect) table.insert(issues, text_sect) self.issue = table.concat(issues, ' ') else local issue = args.issue issue = type(issue) == 'string' and issue ~= '' and issue or nil local text = args.text text = type(text) == 'string' and text or nil local issues = {} table.insert(issues, issue) table.insert(issues, text) self.issue = table.concat(issues, ' ') end end -- Get the self.talk value. local talk = args.talk -- Show talk links on the template page or template subpages if the talk -- parameter is blank. if talk == '' and self.templateTitle and ( mw.title.equals(self.templateTitle, self.title) or self.title:isSubpageOf(self.templateTitle) ) then talk = '#' elseif talk == '' then talk = nil end if talk then -- If the talk value is a talk page, make a link to that page. Else -- assume that it's a section heading, and make a link to the talk -- page of the current page with that section heading. local talkTitle = getTitleObject(talk) local talkArgIsTalkPage = true if not talkTitle or not talkTitle.isTalkPage then talkArgIsTalkPage = false talkTitle = getTitleObject( self.title.text, mw.site.namespaces[self.title.namespace].talk.id ) end if talkTitle and talkTitle.exists then local talkText = 'Соответствующую дискуссию можно найти на' if talkArgIsTalkPage then talkText = string.format( '%s [[%s|%s]].', talkText, talk, talkTitle.prefixedText ) else talkText = string.format( '%s [[%s#%s|странице обсуждения]].', talkText, talkTitle.prefixedText, talk ) end self.talk = talkText end end -- Get other values. self.fix = args.fix ~= '' and args.fix or nil local date if args.date and args.date ~= '' then local status, result = pcall(formatDate, args.date) if status then date = string.format("(<span class='date'>%s</span>)", result) else date = string.format("<span class='error'>(Строка «%s» не является верной датой, пожалуйста, укажите дату в формате <code>ГГГГ-ММ-ДД</code>)</span>", args.date) end elseif args.date == '' and self.isTemplatePage then date = string.format("(<span class='date'>%s</span>)", formatDate( lang:formatDate('Y-m-d') ) ) -- тут возникновения ошибки, связанной с пользовательским вводом, не будет end if date then self.date = string.format(" <span class='mbox-date'>''%s''</span>", date) end self.info = args.info if yesno(args.removalnotice) then self.removalNotice = cfg.removalNotice end if args.shortFix then self.shortFix = args.shortFix end end -- Set the non-collapsible text field. At the moment this is used by all box -- types other than ambox, and also by ambox when small=yes. if self.isSmall then self.text = args.smalltext or args.text else self.text = args.text self.textsmall = args['text-small'] end -- Set the below row. self.below = cfg.below and args.below -- General image settings. self.imageCellDiv = not self.isSmall and cfg.imageCellDiv self.imageEmptyCell = cfg.imageEmptyCell if cfg.imageEmptyCellStyle then self.imageEmptyCellStyle = 'border:none;padding:0px;width:1px' end -- Left image settings. local imageLeft = self.isSmall and args.smallimage or args.image if cfg.imageCheckBlank and imageLeft ~= 'blank' and imageLeft ~= 'none' and imageLeft ~= '' or not cfg.imageCheckBlank and imageLeft ~= 'none' then self.imageLeft = imageLeft if not imageLeft then local imageSize = self.isSmall and (cfg.imageSmallSize or '30x30px') or cfg.imageSize or '40x40px' self.imageLeft = string.format('[[File:%s|%s|alt=]]', self.typeImage or 'Information icon4.svg', imageSize) end end -- Right image settings. local imageRight = self.isSmall and args.smallimageright or args.imageright if not (cfg.imageRightNone and imageRight == 'none') then self.imageRight = imageRight end -- set templatestyles self.base_templatestyles = cfg.templatestyles end function MessageBox:setMainspaceCategories() local args = self.args local cfg = self.cfg local date = nil if not cfg.allowMainspaceCategories then return nil end local nums = {} for _, prefix in ipairs{'cat', 'category', 'all'} do args[prefix .. '1'] = args[prefix] nums = union(nums, getArgNums(args, prefix)) end -- The following is roughly equivalent to the old {{Ambox/category}}. local status, result = pcall(formatDate, args.date, 'xg Y') if status then date = result end date = type(date) == 'string' and date local preposition = 'с' local suffix = 'года' for _, num in ipairs(nums) do local mainCat = args['cat' .. tostring(num)] or args['category' .. tostring(num)] local allCat = args['all' .. tostring(num)] mainCat = type(mainCat) == 'string' and mainCat allCat = type(allCat) == 'string' and allCat if mainCat and date and date ~= '' then local catTitle = string.format('%s %s %s %s', mainCat, preposition, date, suffix) self:addCat(0, catTitle) catTitle = getTitleObject('Категория:' .. catTitle) local status, result = pcall(formatDate, args.date) if not status then self:addCat(0, 'Википедия:Статьи с недопустимым параметром даты в шаблоне-сообщении') end elseif mainCat and (not date or date == '') then self:addCat(0, mainCat) end if allCat then self:addCat(0, allCat) end end end function MessageBox:setTemplateCategories() local args = self.args local cfg = self.cfg -- Add template categories. if cfg.templateCategory then if cfg.templateCategoryRequireName then if self.isTemplatePage then self:addCat(10, cfg.templateCategory) end elseif not self.title.isSubpage then self:addCat(10, cfg.templateCategory) end end -- Add template error categories. if cfg.templateErrorCategory then local templateErrorCategory = cfg.templateErrorCategory local templateCat, templateSort if not self.name and not self.title.isSubpage then templateCat = templateErrorCategory elseif self.isTemplatePage then local paramsToCheck = cfg.templateErrorParamsToCheck or {} local count = 0 for i, param in ipairs(paramsToCheck) do if not args[param] then count = count + 1 end end if count > 0 then templateCat = templateErrorCategory templateSort = tostring(count) end if self.categoryNums and #self.categoryNums > 0 then templateCat = templateErrorCategory templateSort = 'C' end end self:addCat(10, templateCat, templateSort) end end function MessageBox:setAllNamespaceCategories() -- Set categories for all namespaces. if self.invalidTypeError then local allSort = (self.title.namespace == 0 and 'Main:' or '') .. self.title.prefixedText self:addCat('all', 'Википедия:Необходимо исправить параметр в шаблоне-сообщении', allSort) end if self.isSubstituted then self:addCat('all', 'Википедия:Страницы с ошибочно подставленными шаблонами') end if self.isSmall then self:addCat(0, 'Википедия:Страницы с малыми шаблонами-сообщениями') end end function MessageBox:setCategories() if self.title.namespace == 0 then self:setMainspaceCategories() elseif self.title.namespace == 10 then self:setTemplateCategories() end self:setAllNamespaceCategories() end function MessageBox:renderCategories() -- Convert category tables to strings and pass them through -- [[Module:Category handler]]. return categoryHandler{ main = table.concat(self.categories[0] or {}), template = table.concat(self.categories[10] or {}), all = table.concat(self.categories.all or {}), nocat = self.args.nocat, page = self.args.page } end function MessageBox:export() local root = mw.html.create() -- Add the subst check error. if self.isSubstituted and self.name then root:tag('b') :addClass('error') :wikitext(string.format( 'Шаблон <code>%s[[Шаблон:%s|%s]]%s</code> был неккоректно подставлен.', mw.text.nowiki('{{'), self.name, self.name, mw.text.nowiki('}}') )) end -- Conditional TemplateStyles loading if self.base_templatestyles then local frame = mw.getCurrentFrame() root:wikitext(frame:extensionTag{ name = 'templatestyles', args = { src = self.base_templatestyles }, }) end -- Create the box table. local boxTable = root:tag('table') boxTable:attr('id', self.id or nil) for i, class in ipairs(self.classes or {}) do boxTable:addClass(class or nil) end boxTable :cssText(self.style or nil) :attr('role', 'presentation') if self.dataLabel1 then boxTable:attr('data-' .. self.dataLabel1, self.dataValue1) end if self.dataLabel2 then boxTable:attr('data-' .. self.dataLabel2, self.dataValue2) end if self.dataLabel3 then boxTable:attr('data-' .. self.dataLabel3, self.dataValue3) end if self.attrs then boxTable:attr(self.attrs) end -- Add the left-hand image. local row = boxTable:tag('tr') if self.imageLeft then local imageLeftCell = row:tag('td'):addClass('mbox-image') if self.imageCellDiv then -- If we are using a div, redefine imageLeftCell so that the image -- is inside it. Divs use style="width: 52px;", which limits the -- image width to 52px. If any images in a div are wider than that, -- they may overlap with the text or cause other display problems. imageLeftCell = imageLeftCell:tag('div'):css('width', '52px') end imageLeftCell:wikitext(self.imageLeft or nil) elseif self.imageEmptyCell then -- Some message boxes define an empty cell if no image is specified, and -- some don't. The old template code in templates where empty cells are -- specified gives the following hint: "No image. Cell with some width -- or padding necessary for text cell to have 100% width." row:tag('td') :addClass('mbox-empty-cell') :cssText(self.imageEmptyCellStyle or nil) end -- Add the text. local textCell = row:tag('td'):addClass('mbox-text') if self.useCollapsibleTextFields then -- The message box uses advanced text parameters that allow things to be -- collapsible. At the moment, only ambox uses this. textCell:cssText(self.textstyle or nil) local textCellDiv = textCell:tag('div') textCellDiv :addClass('mbox-text-div') :wikitext(self.issue or nil) local textsmallCellDiv = textCell:tag('div') textsmallCellDiv :addClass('mbox-textsmall-div hide-when-compact') :cssText(self.textsmallstyle) :wikitext(self.textsmall or nil) if (self.talk or self.fix) and not self.isSmall then textsmallCellDiv:tag('span') :addClass('hide-when-compact') :wikitext(self.fix and (' ' .. self.fix) or nil) :wikitext(self.talk and (' ' .. self.talk) or nil) end if self.textsmall or self.fix or self.talk then textsmallCellDiv:wikitext(self.date and (' ' .. self.date) or nil) else textCellDiv:wikitext(self.date and (' ' .. self.date) or nil) end if self.info and not self.isSmall then textsmallCellDiv :tag('span') :addClass('hide-when-compact') :wikitext(self.info and (' ' .. self.info) or nil) end if self.removalNotice then textsmallCellDiv:tag('small') :addClass('hide-when-compact') :tag('i') :wikitext(string.format(" (%s)", self.removalNotice)) end if self.shortFix then textCell:tag('div') :addClass('mbox-multiply') :tag('span') :wikitext(string.format("%s", self.shortFix)) :tag('span') :wikitext(self.date and (' ' .. self.date) or nil) end else -- Default text formatting - anything goes. textCell :cssText(self.textstyle or nil) :wikitext(self.text or nil) end -- Add the right-hand image. if self.imageRight then local imageRightCell = row:tag('td'):addClass('mbox-imageright') if self.imageCellDiv then -- If we are using a div, redefine imageRightCell so that the image -- is inside it. imageRightCell = imageRightCell:tag('div'):css('width', '52px') end imageRightCell :wikitext(self.imageRight or nil) end -- Add the below row. if self.below then boxTable:tag('tr') :tag('td') :attr('colspan', self.imageRight and '3' or '2') :addClass('mbox-text') :cssText(self.textstyle or nil) :wikitext(self.below or nil) end -- Add error message for invalid type parameters. if self.invalidTypeError then root:tag('div') :css('text-align', 'center') :wikitext(string.format( 'Этот шаблон-сообщение использует неверный параметр "type=%s", необходимо исправить.', self.type or '' )) end -- Add categories. root:wikitext(self:renderCategories() or nil) return tostring(root) end -------------------------------------------------------------------------------- -- Exports -------------------------------------------------------------------------------- local p, mt = {}, {} function p._exportClasses() -- For testing. return { MessageBox = MessageBox } end function p.main(boxType, args, cfgTables) local box = MessageBox.new(boxType, args, cfgTables or mw.loadData(CONFIG_MODULE)) box:setParameters() box:setCategories() return box:export() end function mt.__index(t, k) return function (frame) if not getArgs then getArgs = require('Module:Arguments').getArgs end return t.main(k, getArgs(frame, {trim = false, removeBlanks = false})) end end return setmetatable(p, mt) f2539b657a9cdadde7c0dd5ad270d3095b2bdd54 Модуль:Category handler 828 15 28 27 2025-01-25T21:00:09Z Vallenland 2 1 версия импортирована Scribunto text/plain -------------------------------------------------------------------------------- -- -- -- CATEGORY HANDLER -- -- -- -- This module implements the {{category handler}} template in Lua, -- -- with a few improvements: all namespaces and all namespace aliases -- -- are supported, and namespace names are detected automatically for -- -- the local wiki. This module requires [[Module:Namespace detect]] -- -- and [[Module:Yesno]] to be available on the local wiki. It can be -- -- configured for different wikis by altering the values in -- -- [[Module:Category handler/config]], and pages can be blacklisted -- -- from categorisation by using [[Module:Category handler/blacklist]]. -- -- -- -------------------------------------------------------------------------------- -- Load required modules local yesno = require('Module:Yesno') -- Lazily load things we don't always need local mShared, mappings local p = {} -------------------------------------------------------------------------------- -- Helper functions -------------------------------------------------------------------------------- local function trimWhitespace(s, removeBlanks) if type(s) ~= 'string' then return s end s = s:match('^%s*(.-)%s*$') if removeBlanks then if s ~= '' then return s else return nil end else return s end end -------------------------------------------------------------------------------- -- CategoryHandler class -------------------------------------------------------------------------------- local CategoryHandler = {} CategoryHandler.__index = CategoryHandler function CategoryHandler.new(data, args) local obj = setmetatable({ _data = data, _args = args }, CategoryHandler) -- Set the title object do local pagename = obj:parameter('demopage') local success, titleObj if pagename then success, titleObj = pcall(mw.title.new, pagename) end if success and titleObj then obj.title = titleObj if titleObj == mw.title.getCurrentTitle() then obj._usesCurrentTitle = true end else obj.title = mw.title.getCurrentTitle() obj._usesCurrentTitle = true end end -- Set suppression parameter values for _, key in ipairs{'nocat', 'categories'} do local value = obj:parameter(key) value = trimWhitespace(value, true) obj['_' .. key] = yesno(value) end do local subpage = obj:parameter('subpage') local category2 = obj:parameter('category2') if type(subpage) == 'string' then subpage = mw.ustring.lower(subpage) end if type(category2) == 'string' then subpage = mw.ustring.lower(category2) end obj._subpage = trimWhitespace(subpage, true) obj._category2 = trimWhitespace(category2) -- don't remove blank values end return obj end function CategoryHandler:parameter(key) local parameterNames = self._data.parameters[key] local pntype = type(parameterNames) if pntype == 'string' or pntype == 'number' then return self._args[parameterNames] elseif pntype == 'table' then for _, name in ipairs(parameterNames) do local value = self._args[name] if value ~= nil then return value end end return nil else error(string.format( 'invalid config key "%s"', tostring(key) ), 2) end end function CategoryHandler:isSuppressedByArguments() return -- See if a category suppression argument has been set. self._nocat == true or self._categories == false or ( self._category2 and self._category2 ~= self._data.category2Yes and self._category2 ~= self._data.category2Negative ) -- Check whether we are on a subpage, and see if categories are -- suppressed based on our subpage status. or self._subpage == self._data.subpageNo and self.title.isSubpage or self._subpage == self._data.subpageOnly and not self.title.isSubpage end function CategoryHandler:shouldSkipBlacklistCheck() -- Check whether the category suppression arguments indicate we -- should skip the blacklist check. return self._nocat == false or self._categories == true or self._category2 == self._data.category2Yes end function CategoryHandler:matchesBlacklist() if self._usesCurrentTitle then return self._data.currentTitleMatchesBlacklist else mShared = mShared or require('Module:Category handler/shared') return mShared.matchesBlacklist( self.title.prefixedText, mw.loadData('Module:Category handler/blacklist') ) end end function CategoryHandler:isSuppressed() -- Find if categories are suppressed by either the arguments or by -- matching the blacklist. return self:isSuppressedByArguments() or not self:shouldSkipBlacklistCheck() and self:matchesBlacklist() end function CategoryHandler:getNamespaceParameters() if self._usesCurrentTitle then return self._data.currentTitleNamespaceParameters else if not mappings then mShared = mShared or require('Module:Category handler/shared') mappings = mShared.getParamMappings(true) -- gets mappings with mw.loadData end return mShared.getNamespaceParameters( self.title, mappings ) end end function CategoryHandler:namespaceParametersExist() -- Find whether any namespace parameters have been specified. -- We use the order "all" --> namespace params --> "other" as this is what -- the old template did. if self:parameter('all') then return true end if not mappings then mShared = mShared or require('Module:Category handler/shared') mappings = mShared.getParamMappings(true) -- gets mappings with mw.loadData end for ns, params in pairs(mappings) do for i, param in ipairs(params) do if self._args[param] then return true end end end if self:parameter('other') then return true end return false end function CategoryHandler:getCategories() local params = self:getNamespaceParameters() local nsCategory for i, param in ipairs(params) do local value = self._args[param] if value ~= nil then nsCategory = value break end end if nsCategory ~= nil or self:namespaceParametersExist() then -- Namespace parameters exist - advanced usage. if nsCategory == nil then nsCategory = self:parameter('other') end local ret = {self:parameter('all')} local numParam = tonumber(nsCategory) if numParam and numParam >= 1 and math.floor(numParam) == numParam then -- nsCategory is an integer ret[#ret + 1] = self._args[numParam] else ret[#ret + 1] = nsCategory end if #ret < 1 then return nil else return table.concat(ret) end elseif self._data.defaultNamespaces[self.title.namespace] then -- Namespace parameters don't exist, simple usage. return self._args[1] end return nil end -------------------------------------------------------------------------------- -- Exports -------------------------------------------------------------------------------- local p = {} function p._exportClasses() -- Used for testing purposes. return { CategoryHandler = CategoryHandler } end function p._main(args, data) data = data or mw.loadData('Module:Category handler/data') local handler = CategoryHandler.new(data, args) if handler:isSuppressed() then return nil end return handler:getCategories() end function p.main(frame, data) data = data or mw.loadData('Module:Category handler/data') local args = require('Module:Arguments').getArgs(frame, { wrappers = data.wrappers, valueFunc = function (k, v) v = trimWhitespace(v) if type(k) == 'number' then if v ~= '' then return v else return nil end else return v end end }) return p._main(args, data) end return p b74dd63857b24904ac452429b11213f18647471f Модуль:Calendar 828 16 30 29 2025-01-25T21:00:09Z Vallenland 2 1 версия импортирована Scribunto text/plain local p = {} -- Необходимые модули и переменные local getArgs = require('Module:Arguments').getArgs local yesno = require('Module:Yesno') local mwlang = mw.getContentLanguage() local err = "―" -- NthDay nil result local tCon = table.concat -- 00) Блок многократно используемых списков local bool_to_number={ [true]=1, [false]=0 } local monthlang = {"января","февраля","марта","апреля","мая","июня","июля","августа","сентября","октября","ноября","декабря"} local month_to_num = {["января"]=1,["февраля"]=2,["марта"]=3,["апреля"]=4,["мая"]=5,["июня"]=6, ["июля"]=7,["августа"]=8,["сентября"]=9,["октября"]=10,["ноября"]=11,["декабря"]=12,["-"]=""} local monthd = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} local params = { {"г", "g"}, {"ю", "j"}} local comment = { '<span style="border-bottom: 1px dotted; cursor: help" title="по юлианскому календарю">','</span>'} -- duplicates: -- AST, BST, CST, ECT, IST, MST, PST, SST, local known_tzs = { ACDT='+10:30', ACST='+09:30', ACT ='+08:00', ADT ='-03:00', AEDT ='+11:00', AEST='+10:00', AFT ='+04:30', AKDT='-08:00', AKST ='-09:00', AMST ='+05:00', AMT ='+04:00', ART ='-03:00', AST ='+03:00', AST ='+04:00', AST ='+03:00', AST ='-04:00', AWDT='+09:00', AWST='+08:00', AZOST='-01:00', AZT ='+04:00', BDT ='+08:00', BIOT='+06:00', BIT ='-12:00', BOT ='-04:00', BRT ='-03:00', BST ='+06:00', BST ='+01:00', BTT ='+06:00', CAT ='+02:00', CCT ='+06:30', CDT ='-05:00', CEDT='+02:00', CEST='+02:00', CET ='+01:00', CHAST='+12:45', CIST='-08:00', CKT ='-10:00', CLST='-03:00', CLT ='-04:00', COST ='-04:00', COT ='-05:00', CST ='-06:00', CST ='+08:00', CVT ='-01:00', CXT ='+07:00', CHST='+10:00', DFT ='+01:00', EAST='-06:00', EAT ='+03:00', ECT ='-04:00', ECT ='-05:00', EDT ='-04:00', EEDT='+03:00', EEST ='+03:00', EET ='+02:00', EST ='-05:00', FJT ='+12:00', FKST='-03:00', FKT ='-04:00', GALT ='-06:00', GET ='+04:00', GFT ='-03:00', GILT='+12:00', GIT ='-09:00', GMT ='+00:00', GST ='-02:00', GYT ='-04:00', HADT='-09:00', HAST ='-10:00', HKT ='+08:00', HMT ='+05:00', HST ='-10:00', IRKT='+08:00', IRST ='+03:30', IST ='+05:30', IST ='+01:00', IST ='+02:00', JST ='+09:00', KRAT ='+07:00', KST ='+09:00', LHST='+10:30', LINT='+14:00', MAGT='+11:00', MDT ='-06:00', MIT ='-09:30', MSD ='+04:00', MSK ='+03:00', MST ='+08:00', MST ='-07:00', MST ='+06:30', MUT ='+04:00', NDT ='-02:30', NFT ='+11:30', NPT ='+05:45', NST ='-03:30', NT ='-03:30', OMST='+06:00', PDT ='-07:00', PETT ='+12:00', PHOT ='+13:00', PKT ='+05:00', PST ='-08:00', PST ='+08:00', RET ='+04:00', SAMT ='+04:00', SAST='+02:00', SBT ='+11:00', SCT ='+04:00', SLT ='+05:30', SST ='-11:00', SST ='+08:00', TAHT='-10:00', THA ='+07:00', UTC ='+00:00', UYST ='-02:00', UYT ='-03:00', VET ='-04:30', VLAT='+10:00', WAT ='+01:00', WEDT ='+01:00', WEST='+01:00', WET ='+00:00', YAKT='+09:00', YEKT ='+05:00', -- US Millitary (for RFC-822) Z='+00:00', A='-01:00', M='-12:00', N='+01:00', Y='+12:00', } local category = { ["no_parameters"]= "<!--[[Категория:Модуль:Calendar:Страницы без параметров]]-->", ["incomplete_parameters"]= "<!--[[Категория:Модуль:Calendar:Страницы с неполными или некорректными параметрами]]-->", ["without_verification"]= "<!--[[Категория:Модуль:Calendar:Страницы без проверки параметров]]-->", ["erroneous_parameters"]= "<!--[[Категория:Модуль:Calendar:Страницы с ошибочными параметрами]]-->" } -- несколько параметров передаются вместе с кодом ошибки в таблице, один может быть передан простым значением local e = { ["start"]="<span class=error>Ошибка: ", ["ending"]=".</span>", ["no_pattern_match"]="строка «%s» не совпадает с заданными паттернами", ["no_valid_date"]="дата «%s» не является корректной", ["wrong_jd"]="юлианская дата %s вне диапазона", ["no_data"]="нет входящих данных", ["too_many_arguments"]="ожидается менее %i аргументов", ["too_little_arguments"]="ожидается более %i аргументов", ["wrong_calculation"]="даты %s и %s не прошли проверку, %s дней разница", ["unknown_param"]="параметр %s неизвестен", ["unknown_error"]="неизвестная ошибка", ["tech_error"]="ошибка в функции %s", ["box_date"]="строка «%s» не является верной датой, пожалуйста, укажите дату в формате ГГГГ-ММ-ДД" -- [""]="", } local tzs_names = {"ACDT","ACST","ACT","ADT","AEDT","AEST","AFT","AKDT","AKST", "AMST","AMT","ART","AST","AST","AST","AST","AWDT","AWST","AZOST","AZT","BDT", "BIOT","BIT","BOT","BRT","BST","BST","BTT","CAT","CCT","CDT","CEDT","CEST", "CET","CHAST","CIST","CKT","CLST","CLT","COST","COT","CST","CST","CVT","CXT", "CHST","DFT","EAST","EAT","ECT","ECT","EDT","EEDT","EEST","EET","EST","FJT", "FKST","FKT","GALT","GET","GFT","GILT","GIT","GMT","GST","GYT","HADT","HAST", "HKT","HMT","HST","IRKT","IRST","IST","IST","IST","JST","KRAT","KST","LHST", "LINT","MAGT","MDT","MIT","MSD","MSK","MST","MST","MST","MUT","NDT","NFT", "NPT","NST","NT","OMST","PDT","PETT","PHOT","PKT","PST","PST","RET","SAMT", "SAST","SBT","SCT","SLT","SST","SST","TAHT","THA","UTC","UYST","UYT","VET", "VLAT","WAT","WEDT","WEST","WET","YAKT","YEKT","Z","A","M","N","Y","MSK"} local pattern = { -- для распознавания дат, переданных одним строчным параметром {"(-?%d%d%d%d?)[-%.%s/\\](%d%d)[-%.%s/\\](%d%d)", ["order"] = {3,2,1} }, -- yyyy mm dd {"(%d+)[-%.%s/\\](%d+)[-%.%s/\\](%d%d%d%d?)", ["order"] = {1,2,3} }, -- dd mm yyyy {"(%d%d)[-%.%s/\\](%d%d%d%d?)", ["order"] = {2,3} }, -- mm yyyy {"(%d%d%d%d?)[-%.%s/\\](%d%d)", ["order"] = {3,2} }, -- yyyy mm {"(%d+)%s(%l+)%s(%d%d%d%d?)", ["order"] = {1,2,3} }, -- d mmm y {"(%l+)%s(%d+),?%s(%d%d%d%d?)", ["order"] = {2,1,3} }, -- mmm d, y {"(%l+)%s(%d%d%d%d?)", ["order"] = {2,3} }, -- mmm y } local time_units = {"year","month","day"} --не используется --[[ local time_units = {"second", "minute", "hour", "day_of_month", "day_of_week", "day_of_year", "week", "month", "year", "year_of_century", "century"} ]]-- -- напоминание чтобы сделать более точные пересчёты - с часами / расчёт длительностей периодов local mnlang = {"ru_G", "ru_N", "en", "en_S", "de", "fr"} local month_lang = { ["ru_G"] = {"января","февраля","марта","апреля","мая","июня", "июля","августа","сентября","октября","ноября","декабря"}, ["ru_N"] = {"январь","февраль","март","апрель","май","июнь", "июль","август","сентябрь","октябрь","ноябрь","декабрь"}, ["en"] = {"january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december"}, ["en_S"] = {"jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"}, ["de"] = {"januar", "februar", "märz", "april", "mai", "juni", "juli", "august", "september", "oktober", "november", "dezember"}, ["fr"] = {"janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre"} } -- заполняется автоматически local reverse_month_lang = {} -- вспомогательная функция для обращения таблиц (смена ключей со значениями) local reverse_table = function (strait_table) local reversed_table = {} for k,v in pairs(strait_table) do reversed_table[v] = k end return reversed_table end -- запуск цикла по заполнению обратных таблиц, необходимых для распознавания дат local filling_months = function (mnlang, month_lang) for i=1, #mnlang do reverse_month_lang[mnlang[i]] = reverse_table(month_lang[mnlang[i]]) end end -- 10) Блок общих функций local function trim(str) if not str then return nil else return str:match'^()%s*$' and '' or str:match'^%s*(.*%S)' end end local function purif(str) if str == "" or str == nil then return nil elseif type(tonumber(str)) == "number" then return math.floor(tonumber(str)) else return nil end -- need .5 -- ,5 number format converter? end local function is(str) if (not str) or (str == "") then return false else return yesno(str,false) end end local function init(num) local output = {} for i=1,num do table.insert(output, {["year"]="", ["month"]="", ["day"]=""}) end return unpack(output) end local function isyear(tbl) if type(tbl) ~= 'table' then return false elseif not tbl["year"] then return false elseif type(tbl["year"]) == 'number' then return true else return false end end local function inbord(val, down, up) return not (type(up) ~= "number" or type(down) ~= "number" or type(val) ~= "number" or up < down or val < down or val > up) end local function shallowcopy(orig) local orig_type = type(orig) local copy if orig_type == 'table' then copy = {} for orig_key, orig_value in pairs(orig) do copy[orig_key] = orig_value end else -- number, string, boolean, etc copy = orig end return copy end local inlist = function ( var, list ) local n = #list local inlist = false for i=1,n do if var == list[i] then inlist = true end end return inlist end -- 20) Блок общих проверочных функций, связанных с датами local function unwarp(tbl) if not tbl then return "" elseif type(tbl) ~= "table" then return tbl elseif (tbl.day or tbl.month or tbl.year) then return (tbl.year or "?").."-"..(tbl.month or "?").."-"..(tbl.day or "?") else return (tbl[3] or "?").."-"..(tbl[2] or "?").."-"..(tbl[1] or "?") end end local function leap_year(y,jul) if (not y) or (type(y) ~= "number") then return false elseif (y % 4) ~= 0 then return false elseif not jul and (y % 100 == 0 and y % 400 ~= 0) then return false else return true end end -- функция для вычисления последнего дня месяца для юлианского и григорианского календарей local function month_end_day (month,year,is_julian) local month_end_day = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} -- если не задан год, дата 29 февраля считается допустимой if not month or type(month) ~= "number" or month < 1 or month > 12 then return nil elseif month ~= 2 or not year then return month_end_day[month] elseif month == 2 and (year % 4) == 0 and not ((not is_julian) and (year % 100 == 0 and year % 400 ~= 0)) then return 29 elseif month == 2 then return 28 else return nil -- в случае не целого значения входящих параметров или при иных непредусмотренных событиях end end local function isdate ( chain , jul ) -- можно использовать для проверки таблиц с полями day, month, year if not chain then return false elseif (not type(chain) == "table") or (not inbord(chain.year,-9999,9999)) or (not inbord(chain.month,1,12)) or (not inbord(chain.day,1,31)) or chain.day > monthd[chain.month] -- or chain.year == 0 then return false elseif chain.month == 2 and chain.day == 29 and not leap_year(chain.year,jul) then return false else return true end -- check for other calendars needed? end local function ispartdate ( chain ) if not chain then return false elseif not (type(chain) == "table") then return false elseif (inbord(chain.year,-9999,9999) or inbord(chain.month,1,12) or inbord(chain.day,1,31)) then return true else return false end -- partial date -- more detailed check for 31.02.0000 needed -- check for other calendars needed end -- from date1 to date2 in one year (beetwen jan-dec, dec-jan needed) local function partdist(date1,date2) local mont, dist = 0, 0 local d1d, d1m, d2d, d2m = (date1["day"] or ""), (date1["month"] or ""),(date2["day"] or ""), (date2["month"] or "") if not (inbord(d1d,1,31) and inbord(d2d,1,31)) then return false end -- нужна доп. проверка частичных дат на корректность if (inbord(d1m,1,12) or inbord(d2m,1,12)) and (d1m == "" or d2m == "") then mont = purif(date1["month"] or date2["month"]) d1m, d2m = mont, mont end -- mw.log("📏 day: " ..d1d .."->"..d2d.." month: ".. d1m.."->"..d2m ) if (inbord(d1m,1,12) and d1d <= monthd[d1m]) and (inbord(d2m,1,12) and d2d <= monthd[d2m]) then if d2m == d1m then dist = d2d - d1d else dist = monthd[d1m] - d1d + d2d end return dist else return math.huge end end local function dmdist(d1,d2) local p1,p2 = math.huge,math.huge if not not partdist(d1,d2) then p1=partdist(d1,d2) end if not not partdist(d2,d1) then p1=partdist(d2,d1) end -- if (not p1) or (not p2) then -- return (p1 or "") .. (p2 or "") -- else -- mw.log("d1, d2 = " .. undate(d1) .. ", " .. undate(d2)) return math.min(tonumber(partdist(d1,d2)) or math.huge,tonumber(partdist(d2,d1)) or math.huge) -- end end -- 30) Блок функций для обработки ввода-вывода дат local function undate(tbl) if not tbl then return "" else return (tbl.year or "").."-"..(tbl.month or "").."-"..(tbl.day or "") end end -- функция для нормализации значений дат и перевода месяцев в числа local function numerize(str) if type(str) == "number" then return math.floor(str) elseif str == "" or str == nil or type(str) ~= "string" then return nil elseif type(tonumber(str)) == "number" then return math.floor(tonumber(str)) else for i=1, #mnlang do if inlist(mw.ustring.lower(str),month_lang[mnlang[i]]) then return reverse_month_lang[mnlang[i]][mw.ustring.lower(str)] end end end end -- функция распознавания даты, переданной одной строкой local function parse_date(date_string) if type(date_string) ~= "string" or date_string == "" then return nil end local out_date_str = {"","",""} local error_data = {} for i=1, #pattern do local result_1, result_2, result_3 = mw.ustring.match(mw.ustring.lower(date_string),pattern[i][1]) if (result_1 or "") > "" then out_date_str[pattern[i].order[1]] = result_1 out_date_str[pattern[i].order[2]] = result_2 if (pattern[i].order[3]) then out_date_str[pattern[i].order[3]] = result_3 end -- mw.log("Паттерн " .. i .. ", строка: " .. date_string) break end end local date = { ["day"] =numerize(out_date_str[1]), ["month"]=numerize(out_date_str[2]), ["year"] =numerize(out_date_str[3])} return date --, error_data end ----[[ УСТАРЕЛО ]]---- local numstr2date = function(numstr) local format = "Y-m-d" local iso_date = mwlang:formatDate(format,numstr) local y,m,d = string.match(iso_date, "(%d+)-(%d+)-(%d+)") local dateout = {["year"]=purif(y), ["month"]=purif(m), ["day"]=purif(d)} return dateout end --local numstr2date = function(numstr) -- local nums = {} -- local dateout = {} -- for num in string.gmatch(numstr,"(%d+)") do -- table.insert(nums,purif(num)) -- end -- if #nums ~= 3 then error("В поле даты вместо трёх чисел с разделителями указано " .. #nums) -- elseif not inbord(nums[2],1,12) then error("Месяц с номером " .. nums[2] .. " не найден") -- elseif not inbord(nums[3],1,31) then -- dateout = {["year"]=nums[3], ["month"]=nums[2], ["day"]=nums[1]} -- elseif not inbord(nums[1],1,31) then -- dateout = {["year"]=nums[1], ["month"]=nums[2], ["day"]=nums[3]} -- elseif inbord(nums[1],1,31) then -- dateout = {["year"]=nums[3], ["month"]=nums[2], ["day"]=nums[1]} -- else -- local mwlang = mw.getContentLanguage() -- implement mwlang:formatDate(format,datein,true) here -- return error("Не распознано " .. numstr .. " как дата") -- end -- return dateout --end local function year2lang(numyear,yearmark,wiki) if not numyear then return "" end if not yearmark then yearmark = "" end local output = "" local bcmark = " до н. э." if numyear > 0 then bcmark = "" else numyear = 1 - numyear end if wiki then -- output = tCon({'[[', numyear,' год',bcmark,'|', numyear,']]', " ", yearmark, " ", bcmark}) output = tCon({'[[', numyear,' год',bcmark,'|', trim(numyear .. " " .. yearmark .. " " .. bcmark), ']]'}) else output = tCon({numyear, " ", yearmark, bcmark}) end return trim(output) end local function day2lang(datein,wikidate,wiki,inner_brt) -- if not isdate(wikidate) then wiki = false end if not ispartdate(datein) then return "" end local dm_separ, output = "", nil if (not (not datein.day)) and (not (not datein.month)) then dm_separ = " " end if (not datein.month) then datein.month = "" end if (not datein.day) then datein.day = "" end local monlan = monthlang[datein.month] or "" if wiki and not inner_brt then output = tCon({"[[", wikidate.day, " ", monthlang[wikidate.month] or "", "|", (datein.day or ""), dm_separ, monlan, "]]"}) elseif wiki then output = tCon({"[[", wikidate.day, " ", monthlang[wikidate.month] or "", "|", (datein.day or ""), dm_separ, monlan}) else output = tCon({datein.day, dm_separ, monlan}) end return trim(output) end local function triple_txt2date(d,m,y) -- добавить (args[1]:match("(%a+)") or "-") для нестандартной записи -- mw.ustring.match((m or ""),"(%a+)") local msg = "" local year = purif((y or "-"):match("(%d+)")) local month = purif(month_to_num[string.lower(mw.ustring.match((m or ""),"(%a+)"))]) local day = purif((d or "-"):match("(%d+)")) if not month then msg = category.incomplete_parameters month = purif(month_to_num[string.lower(mw.ustring.match((d or ""),"(%a+)") or "-")]) end if (not day) and ((purif(string.match(m or "","(%d+)") or "") or 32) <= (monthd[month] or 31)) then msg = category.incomplete_parameters day = purif(m:match("(%d+)") or "") end if not year then msg = category.incomplete_parameters year = purif(string.match(m or "","(%d+)") or "") end local dateout = {["year"]=year, ["month"]=month, ["day"]=day, ["msg"]=msg} return dateout end local function glue(d1,m1,y1,d2,m2,y2) if (not d1) and (not m1) and (not y1) and (not d2) and (not m2) and (not y2) then return category.incomplete_parameters end local gd,gm,gy,jd,jm,jy = (d1 or ""), (m1 or ""), (y1 or ""), (d2 or ""), (m2 or ""), (y2 or "") --mw.log(tCon({gd,gm,gy,jd,jm,jy})) local gm_sep = {" [["," год|","]]"} if (not gy) or (gy == "") then gm_sep = {"","",""} end return tCon({comment[1],trim(trim(jd .. " " .. jm) .. " " .. jy ), comment[2]," ([[",trim(gd .. " " .. gm),"]]",gm_sep[1],(gy:match("(%d+)") or ""), gm_sep[2],gy,gm_sep[3],")",category.incomplete_parameters}) end -- добавить отображение без года local function double_couple(jdate, gdate, wd, wm, wy, sq_brts, yearmark) local msg = "" msg = (jdate.msg or "") .. (gdate.msg or "") local cd = {} local jd = shallowcopy(jdate) local gd = shallowcopy(gdate) local left = "(" local right = ")" if sq_brts then left = "&#091;" right = "&#093;" end if (not isdate(jdate,true)) then return error((jdate.day or "") .. "." .. (jdate.month or "") .."." .. (jdate.year or "") .. " неподходящая дата") elseif (not isdate(gdate)) then return error((gdate.day or "") .. "." .. (gdate.month or "") .."." .. (gdate.year or "") .. " неподходящая дата") end if jd.year == gd.year then cd.year = gd.year gd.year, jd.year = nil, nil end if jd.month == gd.month then cd.month = gd.month gd.month, jd.month = nil, nil end if (not not cd.month) and wm then return tCon({comment[1] .. trim(day2lang(jd,jdate,false) .. " " .. year2lang(jd.year,yearmark,false)) .. comment[2], trim(left .. day2lang(gd,gdate,wd,wm) .. " " .. year2lang(gd.year,yearmark,wy)) .. right, day2lang(cd,gdate,false) .. "]]", trim(year2lang(cd.year,yearmark,wy)..msg)}, " ") end return tCon({comment[1] .. trim(day2lang(jd,jdate,false) .. " " .. year2lang(jd.year,yearmark,false)) .. comment[2], trim(left .. day2lang(gd,gdate,wd) .. " " .. year2lang(gd.year,yearmark,wy)) .. right, trim(day2lang(cd,gdate,false)), trim(year2lang(cd.year,yearmark,wy)..msg)}, " ") end -- 40) Блок функций для перевода дат с использованием [[Юлианская дата]] local function gri2jd( datein ) if not isdate(datein) then return error((datein.day or "") .. "." .. (datein.month or "") .."." .. (datein.year or "") .. " неподходящая дата") end local year = datein.year local month = datein.month local day = datein.day -- jd calculation local a = math.floor((14 - month)/12) local y = year + 4800 - a local m = month + 12*a - 3 local offset = math.floor(y/4) - math.floor(y/100) + math.floor(y/400) - 32045 local jd = day + math.floor((153*m + 2)/5) + 365*y + offset -- jd validation local low, high = -1931076.5, 5373557.49999 if not (low <= jd and jd <= high) then return error((datein.day or "") .. "." .. (datein.month or "") .. "." .. (datein.year or "") .. " выходит за пределы разрешённого диапазона") end return jd end local function jd2jul( jd ) if type(jd) ~= "number" then return error("Промежуточная переменная " .. (jd or "") .. " не является числом") end -- calendar date calculation local c = jd + 32082 local d = math.floor((4*c + 3)/1461) local e = c - math.floor(1461*d/4) local m = math.floor((5*e + 2)/153) local year_out = d - 4800 + math.floor(m/10) local month_out = m + 3 - 12*math.floor(m/10) local day_out = e - math.floor((153*m + 2)/5) + 1 -- output local dateout = {["year"]=year_out, ["month"]=month_out, ["day"]=day_out} return dateout end local function jul2jd( datein ) if not isdate(datein,true) then return error((datein.day or "") .. "." .. (datein.month or "") ..".".. (datein.year or "") .. " неподходящая дата") end local year = datein.year local month = datein.month local day = datein.day -- jd calculation local a = math.floor((14 - month)/12) local y = year + 4800 - a local m = month + 12*a - 3 local offset = math.floor(y/4) - 32083 local jd = day + math.floor((153*m + 2)/5) + 365*y + offset -- jd validation local low, high = -1930999.5, 5373484.49999 if not (low <= jd and jd <= high) then return error((datein.day or "") .. "." .. (datein.month or "") .."." .. (datein.year or "") .. " выходит за пределы разрешённого диапазона") end return jd end local function jd2gri( jd ) if type(jd) ~= "number" then return error("Промежуточная переменная " .. (jd or "") .. " не является числом") end -- calendar date calculation local a = jd + 32044 local b = math.floor((4*a + 3) / 146097) local c = a - math.floor(146097*b/4) local d = math.floor((4*c+3)/1461) local e = c - math.floor(1461*d/4) local m = math.floor((5*e+2)/153) local day_out = e - math.floor((153*m+2)/5)+1 local month_out = m + 3 - 12*math.floor(m/10) local year_out = 100*b + d - 4800 + math.floor(m/10) -- output local dateout = {["year"]=year_out, ["month"]=month_out, ["day"]=day_out} return dateout end local function astroyear(num, bc) if not num then return error() elseif type(num) ~= "number" then return error() end if num < 1 then return num end if not bc then return num else return 1 - num end end local function recalc(datein,calend) if inlist(calend,params[1]) then return jd2jul(gri2jd(datein)), datein elseif inlist(calend,params[2]) then return datein, jd2gri(jul2jd(datein)) else error("Параметр " .. (calend or "") .. " не опознан, разрешённые: " .. tCon(params[1]," ") .. " и " .. tCon(params[2]," ")) end end -- 50) Функции для обработки UTC local function utc(str,margin) local d = 1 local dchar = "+" local beginning = "[[UTC" local ending = "]]" local cat = "" local nums = {} local hmarg, timedec = 0, 0 local mmarg = "00" local output = "" -- checking type of input if not margin then margin = 0 elseif type(tonumber(margin)) ~= 'number' then output = "Can't shift by " .. margin error(output) end if type(str) ~= 'string' then error("Нет входящей строки") elseif str:byte(1) == 43 then elseif inbord(str:byte(1),48,57) then cat = "[[Категория:Википедия:Ошибка в часовом поясе НП]]" elseif str:byte(1) == 45 or string.sub(str,1,3) == "−" or string.sub(str,1,1)=="-" then d = -1 else error(string.char(str:byte(1)) .. " недопустимый первый символ") end -- parsing input for num in string.gmatch(str,"(%d+)") do table.insert(nums,purif(num)) end if #nums > 2 then error("Ожидается всего 2 числа, а не " .. #nums) elseif #nums == 0 then error("Необходимо что-то ввести") elseif #nums == 1 then if inbord(nums[1],0,14) then timedec = d*nums[1] + margin else error("Только часы от -14 до 14") end elseif #nums == 2 then if not inbord(nums[1],0,14) then error("Только часы от -14 до 14") elseif not inbord(nums[2],0,59) then error("Минуты только от 0 до 59") else timedec = d*(nums[1] + nums[2]/60) + margin end end if tonumber(timedec) == purif(timedec) then hmarg = timedec else local h, m = math.modf(math.abs(timedec)) hmarg = h mmarg = math.floor(m*60) end if timedec == 0 then dchar = "±" elseif timedec > 0 then elseif timedec < 0 then dchar = "&minus;" end -- output output = beginning .. dchar .. math.abs(hmarg) .. ":" .. string.format("%02d",mmarg) .. ending .. cat return output end -- 60) Блок функций ввода-вывода function p.NthDay( frame ) local args = getArgs(frame, { frameOnly = true }) local num, wday, mont, yea, format = purif(args[1]), purif(args[2]), purif(args[3]), purif(args[4]), args[5] if not format then format = "%d.%m.%y" end if not inbord(num,-5,5) then return error("The number must be between -5 and 5") elseif num == 0 then return error("The number must not be zero") end if not inbord(wday,0,6) then return error("The day of the week must be between 0 and 6") end if not inbord(mont,1,12) then return error("The month must be between 1 and 12") end if not inbord(yea,0,9999) then return error("Wrong year number") end if inbord(num,1,5) then local m_start = os.time{year=yea, month=mont, day=1, hour=0} local m_wds = tonumber(os.date("%w", m_start)) local start_shift = ( (num - bool_to_number[wday >= m_wds]) * 7 - (m_wds - wday) ) * 24 * 60 * 60 local tim = m_start + start_shift if tonumber(os.date("%m", tim)) == mont then return (os.date(format, tim)) else return (err) end elseif inbord(num,-5,-1) then local m_end = os.time{year = yea, month = mont + 1, day = 1, hour = 0} - 24 * 60 * 60 local m_wde = tonumber(os.date("%w", m_end)) local end_shift = ((math.abs(num + 1) + bool_to_number[wday > m_wde]) * 7 + (m_wde - wday)) * 24 * 60 * 60 local tim = m_end - end_shift if tonumber(os.date("%m", tim)) == mont then return (os.date(format, tim)) else return (err) end end end -- =p.ToIso(mw.getCurrentFrame():newChild{title="smth",args={"12 декабря 2020"}}) -- =p.ToIso(mw.getCurrentFrame():newChild{title="smth",args={"1.2.1602"}}) -- =p.ToIso(mw.getCurrentFrame():newChild{title="smth",args={"12.12.2021"}}) -- =p.ToIso(mw.getCurrentFrame():newChild{title="smth",args={"2021.12.12"}}) function p.ToIso( frame ) local args = getArgs(frame, { frameOnly = true }) local datein = args[1] -- инициализация, заполнение обратных таблиц, копирование параметров filling_months(mnlang, month_lang) -- парсинг входящей даты по шаблону local date = parse_date(datein) if not (type(date.year) == 'number') then return ("Wrong year: " .. unwarp(date)) end if not (1 <= date.month and date.month <= 12) then return ("Wrong month: " .. unwarp(date)) end if not date.day or not (1 <= date.day and date.day <= month_end_day(date.month,date.year)) then return ("Wrong day: " .. unwarp(date)) end local timedate = os.time{year=date.year, month=date.month, day=date.day} local date = os.date("%Y-%m-%d", timedate) return date end -- =p.BoxDate(mw.getCurrentFrame():newChild{title="smth",args={"12 декабря 2020"}}) -- =p.BoxDate(mw.getCurrentFrame():newChild{title="smth",args={"1.2.1602"}}) -- =p.BoxDate(mw.getCurrentFrame():newChild{title="smth",args={"декабрь 2020"}}) -- =p.BoxDate(mw.getCurrentFrame():newChild{title="smth",args={"12-2020"}}) -- =p.BoxDate(mw.getCurrentFrame():newChild{title="smth",args={"12.12.2021"}}) -- =p.BoxDate(mw.getCurrentFrame():newChild{title="smth",args={"2021.12.12"}}) -- =p.BoxDate(mw.getCurrentFrame():newChild{title="smth",args={"2021.11"}}) -- =p.BoxDate(mw.getCurrentFrame():newChild{title="smth",args={"11.2021"}}) function p.BoxDate( frame ) local args = getArgs(frame, { frameOnly = true }) local txtDateIn, strFormat = args[1], args[2] local txtDateOut, date, status = p.bxDate(txtDateIn, strFormat, params) if status.brk then return error(status.errorText) else return txtDateOut end end function p.bxDate( txtDateIn , strFormat, params ) -- к отладке local txtDateOut, date, status = "", {}, {brk = false, errorCat = "", errorText = ""} strFormat = strFormat or "j xg Y" -- заглушка - таблица параметров на будущее params = params or {} if not txtDateIn then status.errorText = e.no_data status.errorCat = category.no_parameters status.brk = true else -- заполнение служебных таблиц filling_months(mnlang, month_lang) end if not status.brk then -- парсинг входящей даты по шаблону date = parse_date(txtDateIn) -- заменить сообщения об ошибках на списочные if not (date.year and type(date.year) == 'number') then status.errorText = string.format(e.box_date,txtDateIn) status.errorCat = category.incomplete_parameters status.brk = true end if not inbord(date.month,1,12) then status.errorText = string.format(e.box_date,txtDateIn) status.errorCat = category.incomplete_parameters status.brk = true end if not date.day and string.find(strFormat,"[dDjlNwzW]") then strFormat = trim(string.gsub(string.gsub(strFormat,"xg","F"),"[dDjlNwzW]","")) elseif not date.day then elseif not inbord(date.day,1,month_end_day(date.month,date.year)) then status.errorText = string.format(e.box_date,txtDateIn) status.errorCat = category.incomplete_parameters status.brk = true end end if not status.brk then txtDateOut = mwlang:formatDate(strFormat,tCon({date.year,date.month,date.day},"-"),true) end return txtDateOut, date, status end function p.ToDate( frame ) -- возможно неиспользуемая local args = getArgs(frame, { frameOnly = true }) local mwlang = mw.getContentLanguage() local datein = args[1] local format = "j xg Y" if not string.match(datein, "%p") then return datein elseif not args[2] then else format = args[2] end return mwlang:formatDate(format,datein,true) end -- =p.unitime(mw.getCurrentFrame():newChild{title="smth",args={"−1:30","1"}}) function p.unitime( frame ) local args = getArgs(frame, { frameOnly = true }) local DST = 0 if not args[2] then else DST = 1 end local utcin = "" local input = args[1] if not input then return "" end if inlist(input:upper(),tzs_names) then utcin = known_tzs[input:upper()] elseif (string.sub(input:upper(),1,3) == 'UTC') and (string.len(input) < 10) then utcin = string.sub(input,4) else if string.sub(input,1,1) == '[' or string.sub(input,1,1) == '{' or string.sub(input,1,1):upper() == 'U' or string.sub(input,1,1):upper() == 'M' then return input -- elseif not string.find(string.upper(string.sub(input,1,1)),"[\65-\90]") or -- not string.find(string.upper(string.sub(input,1,1)),"[\192-\223]") then -- return input else utcin = input end end -- elseif string.sub(input,1,3) ~= "−" then utcin = input -- or not (not input:find("[А-я]")) при наличии в строке юникода не работает local output = "" if DST == 0 then output = utc(utcin) else output = utc(utcin) .. ", [[летнее время|летом]] " .. utc(utcin,DST) end return output end -- УСТАРЕЛО -- =p.OldDate(mw.getCurrentFrame():newChild{title="smth",args={"20.02.2020","ю",["bc"]="1",["wd"]="1",["wy"]="1",["sq_brts"]="1",["yearmark"]="г."}}) function p.OldDate( frame ) local args = getArgs(frame, { frameOnly = true }) if not args[1] then return err end local gdate, jdate = {}, {} local strin = args[1] local cal = args[2]:lower() or "г" local bc = is(args["bc"]) local wd = is(args["wd"]) local wm = is(args["wm"]) local wy = is(args["wy"]) if not wd then wm = false end local sq_brts = is(args["sq_brts"]) local yearmark = "года" if yesno(args["yearmark"]) then elseif yesno(args["yearmark"]) == false then yearmark = "" else yearmark = trim(args["yearmark"]) or "года" end -- local infocard = is(args["infocard"]) -- local catName = args["catName"] or false local datein = numstr2date(strin) datein.year = astroyear(datein.year, bc) jdate, gdate = recalc(datein,cal) return double_couple(jdate, gdate, wd, wm, wy, sq_brts, yearmark) end -- =p.NewDate(mw.getCurrentFrame():newChild{title="Salt",args={"2020-02-20"}}) -- =p.NewDate(mw.getCurrentFrame():newChild{title="smth",args={"20.02.2020","ю",["bc"]="1",["wd"]="1",["wy"]="1",["sq_brts"]="1",["yearmark"]="г."}}) -- =p.NewDate(mw.getCurrentFrame():newChild{title="smth",args={"20.02.2020",["bc"]="0",["wd"]="1",["wy"]="1",["sq_brts"]="0",["yearmark"]=""}}) function p.NewDate( frame ) local args = getArgs(frame, { frameOnly = true }) if not args[1] then return err end local strin = args[1] local year, month, day if not not strin:match( "(-?%d%d%d%d%d)-(%d%d)-(%d%d)" ) then year, month, day = strin:match( "(-?%d%d%d%d%d)-(%d%d)-(%d%d)" ) elseif not not strin:match( "(-?%d+)-(%d+)-(%d+)" ) then year, month, day = strin:match( "(-?%d+)-(%d+)-(%d+)" ) elseif not not strin:match( "(%d%d)%.(%d%d)%.(-?%d%d%d%d%d)" ) then day, month, year = strin:match( "(%d%d)%.(%d%d)%.(-?%d%d%d%d%d)" ) elseif not not strin:match( "(%d+)%.(%d+)%.(-?%d+)" ) then day, month, year = strin:match( "(%d+)%.(%d+)%.(-?%d+)" ) end if not year then return error(args[1] .. " не подходит под форматы yyyy-mm-dd или dd.mm.yyyy") end local cal = "г" if (not args[2]) or (args[2] == "") then cal = "г" else cal = args[2]:lower() end local bc,wd,wm,wy,sq_brts = is(args["bc"]), is(args["wd"]), is(args["wd"]) and is(args["wm"]), is(args["wy"]), is(args["sq_brts"]) year = astroyear(purif(year),bc) local datein = {["year"]=purif(year), ["month"]=purif(month), ["day"]=purif(day)} local jdate, gdate = recalc(datein,cal) local yearmark = "года" local ym = args["yearmark"] or "" if yesno(ym) then elseif yesno(ym) == false then yearmark = "" else if not not ym:match("(%d+)") then error("Цифры в обозначении года: " .. ym) else yearmark = trim(ym) or "года" end end return double_couple(jdate, gdate, wd, wm, wy, sq_brts, yearmark) end -- =p.Test(mw.getCurrentFrame():newChild{title="smth",args={}}) -- =p.Test(mw.getCurrentFrame():newChild{title="smth",args={"3","июня",nil,"21","мая"}}) -- =p.Test(mw.getCurrentFrame():newChild{title="smth",args={"28 августа","","1916 года","15"}}) -- =p.Test(mw.getCurrentFrame():newChild{title="smth",args={"3","июня","1900","21","мая"}}) -- =p.Test(mw.getCurrentFrame():newChild{title="smth",args={"6","июня","1889 год","25","мая"}}) -- =p.Test(mw.getCurrentFrame():newChild{title="smth",args={"28","ноября","1917","15"}}) -- =p.Test(mw.getCurrentFrame():newChild{title="smth",args={"28 августа","nil","1916 года","15"}}) -- =p.Test(mw.getCurrentFrame():newChild{title="smth",args={"4","января","1915","22","декабря","1914 года"}}) -- {{OldStyleDate|день (НС)|месяц (НС)|год (НС)|день (СС)|месяц (СС)|год (СС)}} function p.Test( frame ) local args = getArgs(frame, { frameOnly = true }) -- необходима проверка и замена nil на " " --[[mw.log((args[1] or "") .. " " .. (args[2] or "") .. " " .. (args[3] or "") .. " " .. (args[4] or "") .. " " .. (args[5] or "") .. " " .. (args[6] or "")) ]]-- local ingdate = triple_txt2date(args[1],args[2],args[3]) local injdate = triple_txt2date(args[4],args[5],args[6]) local j1date, g1date, j2date, g2date = init(4) mw.log("ingdate-".. (undate(ingdate) or "")) mw.log("injdate-".. (undate(injdate) or "")) local bc,wd,wm,wy,sq_brts,ny = is(args["bc"]), is(args["wd"]), is(args["wd"]) and is(args["wm"]), is(args["wy"]), is(args["sq_brts"]), is(args["ny"]) -- подавление формата для локальных тестов local wd, wm, wy = true, true, true local yearmark = "года" local ym = args["yearmark"] or ((mw.ustring.match((args[3] or ""),"(%a+)") or mw.ustring.match((args[6] or ""),"(%a+)")) or "") -- mw.log("ym " .. ym) if yesno(ym) then elseif yesno(ym) == false then yearmark = "" else if not not ym:match("(%d+)") then error("Цифры в обозначении года: " .. ym) else yearmark = trim(ym) or "года" end end if isdate(ingdate) or isdate(injdate) then if isdate(ingdate) then j1date, g1date = recalc(ingdate,"g") ingdate["full"] = true end if isdate(injdate) then j2date, g2date = recalc(injdate,"j") injdate["full"] = true end if ispartdate(ingdate) and ispartdate(injdate) then mw.log("📏 " .. dmdist(ingdate,injdate)) mw.log("📏 " .. dmdist(j1date,g1date)) mw.log("📏 " .. dmdist(j2date,g2date)) mw.log("📏 " .. dmdist(ingdate,g1date)) mw.log("📏 " .. dmdist(injdate,j2date)) end end if ny then if isyear(j1date) then else j1date["year"] = "" end if isyear(j2date) == nil then else j2date["year"] = "" end if isyear(g1date) == nil then else g1date["year"] = "" end if isyear(g2date) == nil then else g2date["year"] = "" end end if (isdate(j1date) and isdate(g1date) and isdate(j2date) and isdate(g2date)) then if ((j1date.year == j2date.year) and (j1date.month == j2date.month) and (j1date.day == j2date.day)) then return double_couple(j1date, g1date, wd, wm, wy, sq_brts, yearmark) else mw.log("📏 " .. (tostring(dmdist(ingdate,injdate)) or "")) return glue(args[1],args[2],args[3],args[4],args[5],args[6]) -- категория (предположительная разница в днях) и частичный вывод end elseif isdate(j1date) and isdate(g1date) then return double_couple(j1date, g1date, wd, wm, wy, sq_brts, yearmark) -- категория плюс частичная проверка elseif isdate(j2date) and isdate(g2date) then return double_couple(j2date, g2date, wd, wm, wy, sq_brts, yearmark) -- категория плюс частичная проверка elseif (ispartdate(ingdate) and ispartdate(injdate)) then mw.log("ingdate ".. (undate(ingdate) or "")) mw.log("injdate ".. (undate(injdate) or "")) mw.log("j1date " .. (undate(j1date ) or "")) mw.log("j2date " .. (undate(j2date ) or "")) mw.log("g1date " .. (undate(g1date ) or "")) mw.log("g2date " .. (undate(g2date ) or "")) mw.log("📏 " .. (tostring(partdist(ingdate,injdate)) or "").. " — " .. (tostring(partdist(injdate,ingdate)) or "")) return glue(args[1],args[2],args[3],args[4],args[5],args[6]) -- частичный или полный вывод, категория else mw.log("ingdate ".. (undate(ingdate) or "")) mw.log("injdate ".. (undate(injdate) or "")) mw.log("j1date " .. (undate(j1date ) or "")) mw.log("j2date " .. (undate(j2date ) or "")) mw.log("g1date " .. (undate(g1date ) or "")) mw.log("g2date " .. (undate(g2date ) or "")) return err .. category.incomplete_parameters end end return p a4a91f134ad3e3b246b3a6681a4ae438da766df4 Модуль:Message box/configuration 828 17 32 31 2025-01-25T21:00:10Z Vallenland 2 1 версия импортирована Scribunto text/plain -------------------------------------------------------------------------------- -- Message box configuration -- -- -- -- This module contains configuration data for [[Module:Message box]]. -- -------------------------------------------------------------------------------- return { ambox = { types = { speedy = { class = 'ambox-speedy', image = 'Ambox warning pn.svg' }, delete = { class = 'ambox-delete', image = 'Stop hand nuvola.svg' }, content = { class = 'ambox-content', image = 'Emblem-important.svg' }, style = { class = 'ambox-style', image = 'Broom_icon.svg' }, move = { class = 'ambox-move', image = 'Merge-split-transwiki default.svg' }, protection = { class = 'ambox-protection', image = 'Padlock-silver-medium.svg' }, notice = { class = 'ambox-notice', image = 'Information.svg' }, good = { class = 'ambox-good', image = 'Green star boxed.svg' }, serious = { class = 'ambox-serious', image = 'Stop hand nuvola.svg' }, merge = { class = 'ambox-merge', image = 'Merge-split-transwiki default.svg' }, discussion = { class = 'ambox-discussion', image = 'Nuvola apps ksirc.png' } }, default = 'notice', allowBlankParams = {'talk', 'sect', 'date', 'issue', 'fix', 'subst', 'hidden', 'image'}, allowSmall = true, smallParam = 'left', smallClass = 'mbox-small-left', substCheck = true, classes = {'metadata', 'ambox'}, imageEmptyCell = true, imageCheckBlank = true, imageSmallSize = '20x20px', imageCellDiv = true, useCollapsibleTextFields = true, imageRightNone = true, sectionDefault = 'статья', allowMainspaceCategories = true, templateCategory = 'Шаблоны:Шаблоны-сообщения для статей', templateCategoryRequireName = true, templateErrorCategory = 'Шаблоны:Шаблоны-сообщения для статей с пропущенными параметрами', templateErrorParamsToCheck = {'issue', 'fix'}, removalNotice = '[[Help:Maintenance template removal|Learn how and when to remove this template message]]', templatestyles = 'Module:Message box/ambox.css', }, cmbox = { types = { speedy = { class = 'cmbox-speedy', image = 'Ambox warning pn.svg' }, delete = { class = 'cmbox-delete', image = 'Ambox warning pn.svg' }, content = { class = 'cmbox-content', image = 'Ambox important.svg' }, style = { class = 'cmbox-style', image = 'Edit-clear.svg' }, move = { class = 'cmbox-move', image = 'Merge-split-transwiki default.svg' }, protection = { class = 'cmbox-protection', image = 'Padlock-silver-medium.svg' }, notice = { class = 'cmbox-notice', image = 'Information icon4.svg' } }, default = 'notice', showInvalidTypeError = true, classes = {'cmbox'}, imageEmptyCell = true, useCollapsibleTextFields = true, templatestyles = 'Module:Message box/cmbox.css', }, fmbox = { types = { warning = { class = 'fmbox-warning', image = 'Ambox warning pn.svg' }, editnotice = { class = 'fmbox-editnotice', image = 'Information icon4.svg' }, system = { class = 'fmbox-system', image = 'Information icon4.svg' } }, default = 'system', showInvalidTypeError = true, classes = {'fmbox'}, imageEmptyCell = false, imageRightNone = false, useCollapsibleTextFields = true, templatestyles = 'Module:Message box/fmbox.css', }, imbox = { types = { speedy = { class = 'imbox-speedy', image = 'Ambox warning pn.svg' }, delete = { class = 'imbox-delete', image = 'Ambox warning pn.svg' }, content = { class = 'imbox-content', image = 'Ambox important.svg' }, style = { class = 'imbox-style', image = 'Edit-clear.svg' }, move = { class = 'imbox-move', image = 'Merge-split-transwiki default.svg' }, protection = { class = 'imbox-protection', image = 'Padlock-silver-medium.svg' }, license = { class = 'imbox-license licensetpl', image = 'Imbox license.png' -- @todo We need an SVG version of this }, featured = { class = 'imbox-featured', image = 'Cscr-featured.svg' }, notice = { class = 'imbox-notice', image = 'Information icon4.svg' } }, default = 'notice', showInvalidTypeError = true, classes = {'imbox'}, imageEmptyCell = true, below = true, useCollapsibleTextFields = true, templateCategory = 'Шаблоны:Шаблоны-сообщения для файлов', templatestyles = 'Module:Message box/imbox.css', }, ombox = { types = { speedy = { class = 'ombox-speedy', image = 'OOjs UI icon alert-destructive.svg' }, delete = { class = 'ombox-delete', image = 'OOjs UI icon alert-destructive.svg' }, content = { class = 'ombox-content', image = 'OOjs UI icon notice-warning.svg' }, style = { class = 'ombox-style', image = 'Edit-clear.svg' }, move = { class = 'ombox-move', image = 'Imbox move.png' }, protection = { class = 'ombox-protection', image = 'Imbox protection.png' }, notice = { class = 'ombox-notice', image = 'OOjs UI icon info-progressive.svg' } }, default = 'notice', showInvalidTypeError = true, classes = {'ombox'}, allowSmall = true, imageEmptyCell = true, imageRightNone = true, useCollapsibleTextFields = true, templatestyles = 'Module:Message box/ombox.css', }, tmbox = { types = { speedy = { class = 'tmbox-speedy', image = 'Ambox warning pn.svg' }, delete = { class = 'tmbox-delete', image = 'Ambox warning pn.svg' }, content = { class = 'tmbox-content', image = 'Ambox important.svg' }, style = { class = 'tmbox-style', image = 'Edit-clear.svg' }, move = { class = 'tmbox-move', image = 'Merge-split-transwiki default.svg' }, protection = { class = 'tmbox-protection', image = 'Padlock-silver-medium.svg' }, notice = { class = 'tmbox-notice', image = 'Information icon4.svg' } }, default = 'notice', showInvalidTypeError = true, classes = {'tmbox'}, allowSmall = true, imageRightNone = true, imageEmptyCell = true, imageEmptyCellStyle = true, useCollapsibleTextFields = true, templateCategory = 'Шаблоны:Шаблоны-сообщения для страниц обсуждений', templatestyles = 'Module:Message box/tmbox.css', } } 2c0750ec1561e8ec25c0988c411f3c69e4957483 Модуль:Category handler/data 828 18 34 33 2025-01-25T21:00:11Z Vallenland 2 1 версия импортирована Scribunto text/plain -- This module assembles data to be passed to [[Module:Category handler]] using -- mw.loadData. This includes the configuration data and whether the current -- page matches the title blacklist. local data = require('Module:Category handler/config') local mShared = require('Module:Category handler/shared') local blacklist = require('Module:Category handler/blacklist') local title = mw.title.getCurrentTitle() data.currentTitleMatchesBlacklist = mShared.matchesBlacklist( title.prefixedText, blacklist ) data.currentTitleNamespaceParameters = mShared.getNamespaceParameters( title, mShared.getParamMappings() ) return data abbc68048ff698e88dda06b64ecf384bbf583120 Модуль:Category handler/config 828 19 36 35 2025-01-25T21:00:11Z Vallenland 2 1 версия импортирована Scribunto text/plain -------------------------------------------------------------------------------- -- [[Module:Category handler]] configuration data -- -- Language-specific parameter names and values can be set here. -- -- For blacklist config, see [[Module:Category handler/blacklist]]. -- -------------------------------------------------------------------------------- local cfg = {} -- Don't edit this line. -------------------------------------------------------------------------------- -- Start configuration data -- -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- -- Parameter names -- -- These configuration items specify custom parameter names. -- -- To add one extra name, you can use this format: -- -- -- -- foo = 'parameter name', -- -- -- -- To add multiple names, you can use this format: -- -- -- -- foo = {'parameter name 1', 'parameter name 2', 'parameter name 3'}, -- -------------------------------------------------------------------------------- cfg.parameters = { -- The nocat and categories parameter suppress -- categorisation. They are used with Module:Yesno, and work as follows: -- -- cfg.nocat: -- Result of yesno() Effect -- true Categorisation is suppressed -- false Categorisation is allowed, and -- the blacklist check is skipped -- nil Categorisation is allowed -- -- cfg.categories: -- Result of yesno() Effect -- true Categorisation is allowed, and -- the blacklist check is skipped -- false Categorisation is suppressed -- nil Categorisation is allowed nocat = 'nocat', categories = 'categories', -- The parameter name for the legacy "category2" parameter. This skips the -- blacklist if set to the cfg.category2Yes value, and suppresses -- categorisation if present but equal to anything other than -- cfg.category2Yes or cfg.category2Negative. category2 = 'category2', -- cfg.subpage is the parameter name to specify how to behave on subpages. subpage = 'subpage', -- The parameter for data to return in all namespaces. all = 'all', -- The parameter name for data to return if no data is specified for the -- namespace that is detected. other = 'other', -- The parameter name used to specify a page other than the current page; -- used for testing and demonstration. demopage = 'page', } -------------------------------------------------------------------------------- -- Parameter values -- -- These are set values that can be used with certain parameters. Only one -- -- value can be specified, like this: -- -- -- -- cfg.foo = 'value name' -- -- -------------------------------------------------------------------------------- -- The following settings are used with the cfg.category2 parameter. Setting -- cfg.category2 to cfg.category2Yes skips the blacklist, and if cfg.category2 -- is present but equal to anything other than cfg.category2Yes or -- cfg.category2Negative then it supresses cateogrisation. cfg.category2Yes = 'yes' cfg.category2Negative = '¬' -- The following settings are used with the cfg.subpage parameter. -- cfg.subpageNo is the value to specify to not categorise on subpages; -- cfg.subpageOnly is the value to specify to only categorise on subpages. cfg.subpageNo = 'no' cfg.subpageOnly = 'only' -------------------------------------------------------------------------------- -- Default namespaces -- -- This is a table of namespaces to categorise by default. The keys are the -- -- namespace numbers. -- -------------------------------------------------------------------------------- cfg.defaultNamespaces = { [ 0] = true, -- main [ 6] = true, -- file [ 12] = true, -- help [ 14] = true, -- category [100] = true, -- portal [108] = true, -- book } -------------------------------------------------------------------------------- -- Wrappers -- -- This is a wrapper template or a list of wrapper templates to be passed to -- -- [[Module:Arguments]]. -- -------------------------------------------------------------------------------- cfg.wrappers = 'Template:Category handler' -------------------------------------------------------------------------------- -- End configuration data -- -------------------------------------------------------------------------------- return cfg -- Don't edit this line. 373cd107b13a5b00e6a1b7e66a749f12502c849d Модуль:Category handler/shared 828 20 38 37 2025-01-25T21:00:12Z Vallenland 2 1 версия импортирована Scribunto text/plain -- This module contains shared functions used by [[Module:Category handler]] -- and its submodules. local p = {} function p.matchesBlacklist(page, blacklist) for i, pattern in ipairs(blacklist) do local match = mw.ustring.match(page, pattern) if match then return true end end return false end function p.getParamMappings(useLoadData) local dataPage = 'Module:Namespace detect/data' if useLoadData then return mw.loadData(dataPage).mappings else return require(dataPage).mappings end end function p.getNamespaceParameters(titleObj, mappings) -- We don't use title.nsText for the namespace name because it adds -- underscores. local mappingsKey if titleObj.isTalkPage then mappingsKey = 'talk' else mappingsKey = mw.site.namespaces[titleObj.namespace].name end mappingsKey = mw.ustring.lower(mappingsKey) return mappings[mappingsKey] or {} end return p d2d5de1a031e6ce97c242cbfa8afe7a92cb9eca5 Модуль:Category handler/blacklist 828 21 40 39 2025-01-25T21:00:12Z Vallenland 2 1 версия импортирована Scribunto text/plain -- This module contains the blacklist used by [[Module:Category handler]]. -- Pages that match Lua patterns in this list will not be categorised unless -- categorisation is explicitly requested. return { '^Main Page$', -- don't categorise the main page. -- Don't categorise the following pages or their subpages. -- "%f[/\0]" matches if the next character is "/" or the end of the string. '^Wikipedia:Cascade%-protected items%f[/\0]', '^User:UBX%f[/\0]', -- The userbox "template" space. '^User talk:UBX%f[/\0]', -- Don't categorise subpages of these pages, but allow -- categorisation of the base page. '^Wikipedia:Template messages/.*$', '/[aA]rchive' -- Don't categorise archives. } c84948ad9808d5d323408d5d10d5652f748a0550 Модуль:Namespace detect/data 828 22 42 41 2025-01-25T21:00:13Z Vallenland 2 1 версия импортирована Scribunto text/plain -------------------------------------------------------------------------------- -- Namespace detect data -- -- This module holds data for [[Module:Namespace detect]] to be loaded per -- -- page, rather than per #invoke, for performance reasons. -- -------------------------------------------------------------------------------- local cfg = require('Module:Namespace detect/config') local function addKey(t, key, defaultKey) if key ~= defaultKey then t[#t + 1] = key end end -- Get a table of parameters to query for each default parameter name. -- This allows wikis to customise parameter names in the cfg table while -- ensuring that default parameter names will always work. The cfg table -- values can be added as a string, or as an array of strings. local defaultKeys = { 'main', 'talk', 'other', 'subjectns', 'demospace', 'demopage' } local argKeys = {} for i, defaultKey in ipairs(defaultKeys) do argKeys[defaultKey] = {defaultKey} end for defaultKey, t in pairs(argKeys) do local cfgValue = cfg[defaultKey] local cfgValueType = type(cfgValue) if cfgValueType == 'string' then addKey(t, cfgValue, defaultKey) elseif cfgValueType == 'table' then for i, key in ipairs(cfgValue) do addKey(t, key, defaultKey) end end cfg[defaultKey] = nil -- Free the cfg value as we don't need it any more. end local function getParamMappings() --[[ -- Returns a table of how parameter names map to namespace names. The keys -- are the actual namespace names, in lower case, and the values are the -- possible parameter names for that namespace, also in lower case. The -- table entries are structured like this: -- { -- [''] = {'main'}, -- ['wikipedia'] = {'wikipedia', 'project', 'wp'}, -- ... -- } --]] local mappings = {} local mainNsName = mw.site.subjectNamespaces[0].name mainNsName = mw.ustring.lower(mainNsName) mappings[mainNsName] = mw.clone(argKeys.main) mappings['talk'] = mw.clone(argKeys.talk) for nsid, ns in pairs(mw.site.subjectNamespaces) do if nsid ~= 0 then -- Exclude main namespace. local nsname = mw.ustring.lower(ns.name) local canonicalName = mw.ustring.lower(ns.canonicalName) mappings[nsname] = {nsname} if canonicalName ~= nsname then table.insert(mappings[nsname], canonicalName) end for _, alias in ipairs(ns.aliases) do table.insert(mappings[nsname], mw.ustring.lower(alias)) end end end return mappings end return { argKeys = argKeys, cfg = cfg, mappings = getParamMappings() } d224f42a258bc308ef3ad8cc8686cd7a4f47d005 Модуль:Namespace detect/config 828 23 44 43 2025-01-25T21:00:13Z Vallenland 2 1 версия импортирована Scribunto text/plain -------------------------------------------------------------------------------- -- Namespace detect configuration data -- -- -- -- This module stores configuration data for Module:Namespace detect. Here -- -- you can localise the module to your wiki's language. -- -- -- -- To activate a configuration item, you need to uncomment it. This means -- -- that you need to remove the text "-- " at the start of the line. -- -------------------------------------------------------------------------------- local cfg = {} -- Don't edit this line. -------------------------------------------------------------------------------- -- Parameter names -- -- These configuration items specify custom parameter names. Values added -- -- here will work in addition to the default English parameter names. -- -- To add one extra name, you can use this format: -- -- -- -- cfg.foo = 'parameter name' -- -- -- -- To add multiple names, you can use this format: -- -- -- -- cfg.foo = {'parameter name 1', 'parameter name 2', 'parameter name 3'} -- -------------------------------------------------------------------------------- ---- This parameter displays content for the main namespace: -- cfg.main = 'main' ---- This parameter displays in talk namespaces: -- cfg.talk = 'talk' ---- This parameter displays content for "other" namespaces (namespaces for which ---- parameters have not been specified): -- cfg.other = 'other' ---- This parameter makes talk pages behave as though they are the corresponding ---- subject namespace. Note that this parameter is used with [[Module:Yesno]]. ---- Edit that module to change the default values of "yes", "no", etc. -- cfg.subjectns = 'subjectns' ---- This parameter sets a demonstration namespace: -- cfg.demospace = 'demospace' ---- This parameter sets a specific page to compare: cfg.demopage = 'page' -------------------------------------------------------------------------------- -- Table configuration -- -- These configuration items allow customisation of the "table" function, -- -- used to generate a table of possible parameters in the module -- -- documentation. -- -------------------------------------------------------------------------------- ---- The header for the namespace column in the wikitable containing the list of ---- possible subject-space parameters. -- cfg.wikitableNamespaceHeader = 'Namespace' ---- The header for the wikitable containing the list of possible subject-space ---- parameters. -- cfg.wikitableAliasesHeader = 'Aliases' -------------------------------------------------------------------------------- -- End of configuration data -- -------------------------------------------------------------------------------- return cfg -- Don't edit this line. 0e4ff08d13c4b664d66b32c232deb129b77c1a56 Шаблон:Карточка 10 24 46 45 2025-01-25T21:00:14Z Vallenland 2 1 версия импортирована wikitext text/x-wiki {{#if:{{{имя|}}}|{{#ifeq:{{{имя|}}}|-||{{#if:{{{цвет|}}}|{{#tag:templatestyles| |wrapper=.infobox-{{#invoke:Hash|main|{{{имя}}} {{{вверху0|}}} {{{вверху|}}} {{{вверху2|}}}}} |src=Шаблон:Цвет/{{{цвет|}}}.css }}}}}}}}<table class="infobox infobox-{{#invoke:Hash|main|{{{имя}}} {{{вверху0|}}} {{{вверху|}}} {{{вверху2|}}}}} {{{класс_тела|}}}" style="{{{стиль_тела|}}}" {{#if:{{{имя|}}}|{{#ifeq:{{{имя|}}}|-||data-name="{{{имя}}}"}}}} {{#if:{{{from|}}}|{{#ifeq:{{{from|}}}|-||data-from="{{{from}}}"}}}}><!-- Вверху0 -->{{#if:{{{вверху0|}}}|<tr><td colspan="2" class="{{{класс_вверху0|}}}" style="text-align:center; {{{стиль_вверху0|}}}">{{{вверху0}}}</td></tr>}}<!-- Вверху -->{{#if:{{{вверху|}}}|<tr><th colspan="2" scope="colgroup" class="infobox-above {{{класс_вверху|}}}" style="{{{стиль_вверху|}}}">{{{вверху}}}</th></tr>}}<!-- Вверху2 -->{{#if:{{{вверху2|}}}|<tr><td colspan="2" class="{{{класс_вверху2|}}}" style="text-align:center; {{{стиль_вверху2|}}}">{{{вверху2}}}</td></tr>}}<!-- Вверху3 -->{{#if:{{{вверху3|}}}|<tr><td colspan="2" class="{{{класс_вверху3|}}}" style="text-align:center; {{{стиль_вверху3|}}}">{{{вверху3}}}</td></tr>}}<!-- Изображение -->{{#if:{{{изображение|}}}|<tr><td colspan="2" class="infobox-image {{{класс_изображения|}}}" style="{{{стиль_изображения|}}}"> {{{изображение}}} {{#if:{{{подпись|}}}| <div class="media-caption" style="{{{стиль_подписи|}}}">{{{подпись}}}</div>}}</td></tr>}}<!-- Изображение2 -->{{#if:{{{изображение2|}}}|<tr><td colspan="2" class="infobox-image {{{класс_изображения2|}}}" style="{{{стиль_изображения2|}}}"> {{{изображение2}}} {{#if:{{{подпись2|}}}| <div class="media-caption" style="{{{стиль_подписи2|}}}">{{{подпись2}}}</div>}}</td></tr>}}<!-- Изображение3 -->{{#if:{{{изображение3|}}}|<tr><td colspan="2" class="infobox-image {{{класс_изображения3|}}}" style="{{{стиль_изображения3|}}}"> {{{изображение3}}} {{#if:{{{подпись3|}}}| <div class="media-caption" style="{{{стиль_подписи3|}}}">{{{подпись3}}}</div>}}</td></tr>}}<!-- Строки -->{{#invoke:Infobox|renderLines}}<!-- Внизу -->{{Карточка/внизу| стиль_внизу_общий={{{стиль_внизу|}}}| класс_внизу={{{класс_внизу|}}}| внизу={{{внизу|}}}}}<!-- Внизу N -->{{#invoke:Transclude|npc|Карточка/внизу| стиль_внизу_общий={{{стиль_внизу|}}}| стиль_внизу=| класс_внизу=| внизу=}} </table><includeonly><!-- статьи -->{{#if:{{NAMESPACE}}||<!-- -->{{#if:{{{имя|}}}||[[Категория:Статьи с шаблонами-карточками без имени]]}}<!-- -->{{#ifeq:{{{имя|}}}|{{subst:PAGENAME}}|[[Категория:Статьи с шаблонами-карточками без имени]]}}<!-- -->}}<!-- шаблоны -->{{#ifeq:{{NAMESPACENUMBER}}|10|<!-- -->{{#if:{{{имя|}}}||[[Категория:Шаблоны-карточки без имени]]}}<!-- -->{{#ifeq:{{{имя|}}}|{{subst:PAGENAME}}|[[Категория:Шаблоны-карточки без имени]]}}<!-- -->{{#if:{{{название|}}}{{{стиль_названия|}}}|[[Категория:Шаблоны с использованием параметра «название» в шаблоне «Карточка»]]}}<!-- -->{{#if:{{{подпись|}}}{{{стиль_подписи|}}}{{{подпись2|}}}{{{стиль_подписи2|}}}{{{подпись3|}}}{{{стиль_подписи3|}}}|[[Категория:Шаблоны с использованием параметра «подпись» в шаблоне «Карточка»]]}}<!-- -->{{#ifexpr:{{#invoke:Color_contrast|styleratio|{{{стиль_тела|}}}}} < 4.5|[[Категория:Потенциально нечитаемые карточки]]}}<!-- -->{{#ifexpr:{{#invoke:Color_contrast|styleratio|{{{стиль_названия|}}}}} < 4.5|[[Категория:Потенциально нечитаемые карточки]]}}<!-- -->{{#ifexpr:{{#invoke:Color_contrast|styleratio|{{{стиль_вверху|}}}}} < 4.5|[[Категория:Потенциально нечитаемые карточки]]}}<!-- -->{{#ifexpr:{{#invoke:Color_contrast|styleratio|{{{стиль_вверху2|}}}}} < 4.5|[[Категория:Потенциально нечитаемые карточки]]}}<!-- -->{{#ifexpr:{{#invoke:Color_contrast|styleratio|{{{стиль_вверху3|}}}}} < 4.5|[[Категория:Потенциально нечитаемые карточки]]}}<!-- -->{{#ifexpr:{{#invoke:Color_contrast|styleratio|{{{стиль_подписи|}}}}} < 4.5|[[Категория:Потенциально нечитаемые карточки]]}}<!-- -->{{#ifexpr:{{#invoke:Color_contrast|styleratio|{{{стиль_подписи2|}}}}} < 4.5|[[Категория:Потенциально нечитаемые карточки]]}}<!-- -->{{#ifexpr:{{#invoke:Color_contrast|styleratio|{{{стиль_подписи3|}}}}} < 4.5|[[Категория:Потенциально нечитаемые карточки]]}}<!-- -->{{#ifexpr:{{#invoke:Color_contrast|styleratio|{{{стиль_заголовков|}}}}} < 4.5|[[Категория:Потенциально нечитаемые карточки]]}}<!-- -->{{#ifexpr:{{#invoke:Color_contrast|styleratio|{{{стиль_меток|}}}}} < 4.5|[[Категория:Потенциально нечитаемые карточки]]}}<!-- -->{{#ifexpr:{{#invoke:Color_contrast|styleratio|{{{стиль_текста|}}}}} < 4.5|[[Категория:Потенциально нечитаемые карточки]]}}<!-- -->{{#ifexpr:{{#invoke:Color_contrast|styleratio|{{{стиль_внизу|}}}}} < 4.5|[[Категория:Потенциально нечитаемые карточки]]}}<!-- -->{{#ifeq:{{{имя|}}}|{{PAGENAME}}|<!-- -->[[Категория:Шаблоны-карточки по алфавиту|{{ucfirst:{{без начала|{{PAGENAME}}|Карточка }}}}]]<!-- -->{{#if:{{{стиль_тела|}}}{{{стиль_вверху|}}}{{{стиль_заголовков|}}}{{{стиль_внизу|}}}|[[Категория:Википедия:Шаблоны-карточки с явным указанием стилей]]}}<!-- -->}}<!-- -->}}<!-- любое пространство имён -->{{#if:{{{название|}}}{{{стиль_названия|}}}|[[Категория:Википедия:Страницы с использованием параметра «название» в шаблоне «Карточка»]]}}<!-- -->{{#if:{{{подпись|}}}{{{стиль_подписи|}}}{{{подпись2|}}}{{{стиль_подписи2|}}}{{{подпись3|}}}{{{стиль_подписи3|}}}|[[Категория:Википедия:Страницы с использованием параметра «подпись» в шаблоне «Карточка»]]}}</includeonly><noinclude>{{doc}}</noinclude> 5bd0cadc0cad51dc109de7db63622ab36743d386 Шаблон:Yesno 10 25 48 47 2025-01-25T21:00:14Z Vallenland 2 1 версия импортирована wikitext text/x-wiki {{<includeonly>safesubst:</includeonly>#switch: {{<includeonly>safesubst:</includeonly>lc: {{{1|¬}}} }} |no |n |нет |false |0 = {{{no|<!-- null -->}}} | = {{{blank|{{{no|<!-- null -->}}}}}} |¬ = {{{¬|}}} |yes |y |да |true |1 = {{{yes|yes}}} |#default = {{{def|{{{yes|yes}}}}}} }}<noinclude> {{Documentation}} </noinclude> 4e236854c477d07a225c2ab6c016c389b133e8d3 Шаблон:Wikidata 10 26 50 49 2025-01-25T21:00:14Z Vallenland 2 1 версия импортирована wikitext text/x-wiki <includeonly>{{#invoke:Wikidata|formatProperty|property={{{1|}}}|value={{{2|}}}}}</includeonly><noinclude>{{doc}}</noinclude> 9d3d422eca39504b018df6ec0bb047392a7aba7e Шаблон:Карточка/Викисклад 10 27 52 51 2025-01-25T21:00:14Z Vallenland 2 1 версия импортирована wikitext text/x-wiki {{wikidata|p373|{{str rep|{{str rep|{{{1|}}}|Category:|}}|category:|}}|plain=false|text=Медиафайлы на Викискладе|icon={{{icon|}}}|icon_size={{{icon_size|}}}|from={{{from|}}}}}<!-- -->{{#if: {{{nocat|}}}{{NAMESPACE}} || <!-- -->{{#if: {{{1|}}} | [[Категория:Википедия:Ссылка на Викисклад непосредственно в статье]]<!-- -->{{#if: {{wikidata|p373|plain=true}} | {{#ifeq: {{str rep|{{str rep|{{{1|}}}|Category:|}}|category:|}} | {{wikidata|p373|plain=true}} |[[Категория:Википедия:Ссылки на Викисклад в статье и на Викиданных совпадают]]| [[Категория:Википедия:Ссылки на Викисклад в статье и на Викиданных отличаются]] }} | [[Категория:Википедия:Ссылка на Викисклад в статье, но не на Викиданных]] }} }}<!-- --> }}<!-- -->{{#ifeq: {{NAMESPACE}} | Шаблон | {{#if: {{{2|}}} | [[Категория:Википедия:Шаблоны для низа карточек с лишним параметром]] }} }}<!-- --><noinclude> {{doc}} </noinclude> 40ef9a463c772ddbf54feae9e21d4037b692253e Шаблон:Str rep 10 28 54 53 2025-01-25T21:00:15Z Vallenland 2 1 версия импортирована wikitext text/x-wiki <includeonly>{{{{{|safesubst:}}}#invoke:String|replace|source={{{1}}}|{{{2}}}|{{{3}}}|{{{4|1}}}}}</includeonly><noinclude>{{doc}}</noinclude> c75032f150c372324c69a6f62ff4ab1492ad4cfa Шаблон:Карточка/внизу 10 29 56 55 2025-01-25T21:00:15Z Vallenland 2 1 версия импортирована wikitext text/x-wiki <includeonly>{{#if:{{{внизу|}}}|<tr><td colspan="2" class="infobox-below {{{класс_внизу|}}}" style="{{{стиль_внизу_общий|}}};{{{стиль_внизу|}}}">{{{внизу|}}}</td></tr>}}</includeonly><noinclude> {{doc}} </noinclude> 169fb2d10b0847c2fd677eda9f159ba99025198f Модуль:Wikidata 828 31 60 59 2025-01-25T21:00:16Z Vallenland 2 1 версия импортирована Scribunto text/plain ---settings, may differ from project to project local fileDefaultSize = '267x400px' local outputReferences = true local writingSystemElementId = 'Q8209' local langElementId = 'Q7737' ---Ссылки на используемые модули, которые потребуются в 99% случаев загрузки страниц (чтобы иметь на виду при переименовании) local moduleSources = require( 'Module:Sources' ) local WDS = require( 'Module:WikidataSelectors' ) ---Константы ---@type string local CONTENT_LANGUAGE_CODE = mw.language.getContentLanguage():getCode() local p = {} local g_config, g_frame local formatDatavalue, formatEntityId, formatRefs, formatSnak, formatStatement, formatStatementDefault, getSourcingCircumstances, getPropertyParams ---@param obj table ---@param target table ---@param skipEmpty boolean | nil ---@return table local function copyTo( obj, target, skipEmpty ) for key, val in pairs( obj ) do if skipEmpty ~= true or ( val ~= nil and val ~= '' ) then target[ key ] = val end end return target end ---@param prev number | nil ---@param next number | nil ---@return number | nil local function min( prev, next ) if prev == nil or prev > next then return next end return prev end ---@param prev number | nil ---@param next number | nil ---@return number | nil local function max( prev, next ) if prev == nil or prev < next then return next end return prev end ---@param section string ---@param code string ---@return any | nil local function getConfig( section, code ) if g_config == nil then g_config = require( 'Module:Wikidata/config' ) end if not g_config then g_config = {} end if not section then return g_config end if not code then return g_config[ section ] or {} end if not g_config[ section ] then return nil end return g_config[ section ][ code ] end ---@param code string ---@param sortKey string | nil ---@return string local function getCategoryByCode( code, sortKey ) local value = getConfig( 'categories', code ) if not value or value == '' then return '' end if sortKey ~= nil then return '[[Category:' .. value .. '|' .. sortKey .. ']]'; -- экранировать? else return '[[Category:' .. value .. ']]' end end ---@param isoStr string | table ---@return table | nil local function splitISO8601( isoStr ) if 'table' == type( isoStr ) then if isoStr.args and isoStr.args[ 1 ] then isoStr = '' .. isoStr.args[ 1 ] else return 'unknown argument type: ' .. type( isoStr ) .. ': ' .. table.tostring( isoStr ) end end local Y, M, D = ( function( str ) local pattern = "(%-?%d+)%-(%d+)%-(%d+)T" local _Y, _M, _D = mw.ustring.match( str, pattern ) return tonumber( _Y ), tonumber( _M ), tonumber( _D ) end )( isoStr ) local h, m, s = ( function( str ) local pattern = "T(%d+):(%d+):(%d+)%Z" local _H, _M, _S = mw.ustring.match( str, pattern ) return tonumber( _H ), tonumber( _M ), tonumber( _S ) end )( isoStr ) local oh, om = ( function( str ) if str:sub(-1) == "Z" then -- ends with Z, Zulu time return 0, 0 end -- matches ±hh:mm, ±hhmm or ±hh; else returns nils local pattern = "([-+])(%d%d):?(%d?%d?)$" local sign, oh, om = mw.ustring.match( str, pattern ) sign, oh, om = sign or "+", oh or "00", om or "00" return tonumber( sign .. oh ), tonumber( sign .. om ) end )( isoStr ) return { year=Y, month=M, day=D, hour=( h + oh ), min=( m + om ), sec=s } end ---Внутренняя функции для получения границ временного диапазона ---@param time string ---@param precision number ---@return table | nil function p._parseTimeBoundaries( time, precision ) local s = splitISO8601( time ) if not s then return nil end if precision >= 0 and precision <= 8 then local powers = { 1000000000 , 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10 } local power = powers[ precision + 1 ] local left = s.year - ( s.year % power ) return { tonumber( os.time( { year=left, month=1, day=1, hour=0, min=0, sec=0 } ) ) * 1000, tonumber( os.time( { year=left + power - 1, month=12, day=31, hour=29, min=59, sec=58 } ) ) * 1000 + 1999 } end if precision == 9 then return { tonumber( os.time( { year=s.year, month=1, day=1, hour=0, min=0, sec=0} )) * 1000, tonumber( os.time( { year=s.year, month=12, day=31, hour=23, min=59, sec=58} )) * 1000 + 1999 } end if precision == 10 then local lastDays = { 31, 28.25, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } local lastDay = lastDays[ s.month ] return { tonumber( os.time( { year=s.year, month=s.month, day=1, hour=0, min=0, sec=0 } ) ) * 1000, tonumber( os.time( { year=s.year, month=s.month, day=lastDay, hour=23, min=59, sec=58 } ) ) * 1000 + 1999 } end if precision == 11 then return { tonumber( os.time( { year=s.year, month=s.month, day=s.day, hour=0, min=0, sec=0 } ) ) * 1000, tonumber( os.time( { year=s.year, month=s.month, day=s.day, hour=23, min=59, sec=58 } ) ) * 1000 + 1999 } end if precision == 12 then return { tonumber( os.time( { year=s.year, month=s.month, day=s.day, hour=s.hour, min=0, sec=0 } ) ) * 1000, tonumber( os.time( { year=s.year, month=s.month, day=s.day, hour=s.hour, min=59, sec=58 } ) ) * 1000 + 1999 } end if precision == 13 then return { tonumber( os.time( { year=s.year, month=s.month, day=s.day, hour=s.hour, min=s.min, sec=0 } ) ) * 1000, tonumber( os.time( { year=s.year, month=s.month, day=s.day, hour=s.hour, min=s.min, sec=58 } ) ) * 1000 + 1999 } end if precision == 14 then local t = tonumber( os.time( { year=s.year, month=s.month, day=s.day, hour=s.hour, min=s.min, sec=0 } ) ) return { t * 1000, t * 1000 + 999 } end error( 'Unsupported precision: ' .. precision ) end ---Внутренняя функция для получения числового значения времени из snak'а ---@param table snak ---@return number | nil function p._parseTimeFromSnak( snak ) if snak and snak.datavalue and snak.datavalue.value and snak.datavalue.value.time then local timeData = splitISO8601( tostring( snak.datavalue.value.time ) ) timeData.month = math.max( timeData.month, 1 ) timeData.day = math.max( timeData.day, 1 ) return tonumber( os.time( timeData ) ) * 1000 end return nil end ---Функция для формирования категории на основе wikidata/config ---@param options table ---@param entityId string ---@return string local function extractCategory( options, entityId ) if not entityId or not options.category or options.nocat then return '' end if type( entityId ) ~= 'string' then entityId = entityId.id end local claims = WDS.load( entityId, options.category ) if not claims then return '' end for _, claim in pairs( claims ) do if claim and claim.mainsnak and claim.mainsnak.datavalue and claim.mainsnak.datavalue.type == 'wikibase-entityid' then local catEntityId = claim.mainsnak.datavalue.value.id local wbStatus, catSiteLink = pcall( mw.wikibase.getSitelink, catEntityId ) if wbStatus and catSiteLink then return '[[' .. catSiteLink .. ']]' end end end return '' end ---Преобразует строку в булевое значение ---@param valueToParse string ---@return boolean Преобразованное значение, если его удалось распознать, или defaultValue во всех остальных случаях local function toBoolean( valueToParse, defaultValue ) if valueToParse ~= nil then if valueToParse == false or valueToParse == '' or valueToParse == 'false' or valueToParse == '0' then return false end return true end return defaultValue end ---Обрачивает отформатированное значение в инлайновый или блочный тег. ---@param value string value ---@param attributes table of attributes ---@return string HTML tag with value local function wrapValue( value, attributes ) local tagName = 'span' local spacer = '' if string.match( value, '\n' ) or string.match( value, '<t[dhr][ >]' ) or string.match( value, '<div[ >]' ) or string.find( value, 'UNIQ%-%-imagemap' ) then tagName = 'div' spacer = '\n' end local attrString = '' for key, val in pairs( attributes or {} ) do local _key = mw.text.trim( key ) local _value = mw.text.encode( mw.text.trim( val ) ) attrString = attrString .. _key .. '="' .. _value .. '" ' end return '<' .. tagName .. ' ' .. attrString .. '>' .. spacer .. value .. '</' .. tagName .. '>' end ---Wraps formatted snak value into HTML tag with attributes. ---@param value string value of snak ---@param hash string ---@param attributes table of extra attributes ---@return string HTML tag with value local function wrapSnak( value, hash, attributes ) local newAttributes = mw.clone( attributes or {} ) newAttributes[ 'class' ] = ( newAttributes[ 'class' ] or '' ) .. ' wikidata-snak' if hash then newAttributes[ 'data-wikidata-hash'] = hash else newAttributes[ 'class' ] = newAttributes[ 'class' ] .. ' wikidata-main-snak' end return wrapValue( value, newAttributes ) end ---Wraps formatted statement value into HTML tag with attributes. ---@param value string value of statement ---@param propertyId string PID of property ---@param claimId string ID of claim or nil for local value ---@param attributes table of extra attributes ---@return string HTML tag with value local function wrapStatement( value, propertyId, claimId, attributes ) local newAttributes = mw.clone( attributes or {} ) newAttributes[ 'class' ] = newAttributes[ 'class' ] or '' newAttributes[ 'data-wikidata-property-id' ] = string.upper( propertyId ) if claimId then newAttributes[ 'class' ] = newAttributes[ 'class' ] .. ' wikidata-claim' newAttributes[ 'data-wikidata-claim-id' ] = claimId else newAttributes[ 'class' ] = newAttributes[ 'class' ] .. ' no-wikidata' end return wrapValue( value, newAttributes ) end ---Wraps formatted qualifier's statement value into HTML tag with attributes. ---@param value string value of qualifier's statement ---@param qualifierId string PID of qualifier ---@param attributes table of extra attributes ---@return string HTML tag with value local function wrapQualifier( value, qualifierId, attributes ) local newAttributes = mw.clone( attributes or {} ) newAttributes[ 'data-wikidata-qualifier-id' ] = string.upper( qualifierId ) return wrapValue( value, newAttributes ) end ---Функция для получения сущности (еntity) для текущей страницы ---Подробнее о сущностях см. d:Wikidata:Glossary/ru ---@param id string Идентификатор (типа P18, Q42) ---@return table Таблица, элементы которой индексируются с нуля local function getEntityFromId( id ) local entity local wbStatus if id then wbStatus, entity = pcall( mw.wikibase.getEntity, id ) else wbStatus, entity = pcall( mw.wikibase.getEntity ) end return entity end ---Внутренняя функция для формирования сообщения об ошибке ---@param key string Ключ элемента в таблице config.errors (например entity-not-found) ---@return void local function throwError( key ) error( getConfig( 'errors', key ) ) end ---Функция для получения идентификатора сущностей ---@param value table ---@return string local function getEntityIdFromValue( value ) local prefix = '' if value[ 'entity-type' ] == 'item' then prefix = 'Q' elseif value[ 'entity-type' ] == 'property' then prefix = 'P' else throwError( 'unknown-entity-type' ) end return prefix .. value[ 'numeric-id' ] end ---Проверка на наличие специализированной функции в опциях ---@param options table ---@param prefix string ---@return function local function getUserFunction( options, prefix, defaultFunction ) -- проверка на указание специализированных обработчиков в параметрах, -- переданных при вызове if options[ prefix .. '-module' ] or options[ prefix .. '-function' ] then -- проверка на пустые строки в параметрах или их отсутствие if not options[ prefix .. '-module' ] or not options[ prefix .. '-function' ] then throwError( 'unknown-' .. prefix .. '-module' ) end -- динамическая загруза модуля с обработчиком указанным в параметре local formatter = require( 'Module:' .. options[ prefix .. '-module' ] ) if formatter == nil then throwError( prefix .. '-module-not-found' ) end local fun = formatter[ options[ prefix .. '-function' ] ] if fun == nil then throwError( prefix .. '-function-not-found' ) end return fun end return defaultFunction end ---Выбирает свойства по property id, дополнительно фильтруя их по рангу ---@param context table ---@param options table ---@param propertySelector string ---@return table | nil local function selectClaims( context, options, propertySelector ) if not context then error( 'context not specified' ); end if not options then error( 'options not specified' ); end if not options.entityId then error( 'options.entity is missing' ); end if not propertySelector then error( 'propertySelector not specified' ); end local result = WDS.load( options.entityId, propertySelector ) if not result or #result == 0 then return nil end if options.limit and options.limit ~= '' and options.limit ~= '-' then local limit = tonumber( options.limit, 10 ) while #result > limit do table.remove( result ) end end return result end ---Функция для получения значения свойства элемента в заданный момент времени. ---@param entityId string ---@param boundaries table Временные границы ---@param propertyIds table<string> ---@param selectors table<string> ---@return table Таблица соответствующих значений свойства local function getPropertyInBoundaries( context, entityId, boundaries, propertyIds, selectors ) if type( entityId ) ~= 'string' then error( 'type of entityId argument expected string, but was ' .. type(entityId)); end local results = {} if not propertyIds or #propertyIds == 0 then return results end for i, propertyId in ipairs( propertyIds ) do local selector if selectors ~= nil then selector = selectors[ i ] or selectors[ propertyId ] or propertyId else selector = propertyId end local fakeAllClaims = {} fakeAllClaims[ propertyId ] = mw.wikibase.getAllStatements( entityId, propertyId ) local filteredClaims = WDS.filter( fakeAllClaims, selector .. '[rank:preferred, rank:normal]' ) if filteredClaims then for _, claim in pairs( filteredClaims ) do if not boundaries then if not claim.qualifiers or not claim.qualifiers.P582 then table.insert( results, claim.mainsnak ) end else local startBoundaries = p.getTimeBoundariesFromQualifier( context.frame, context, claim, 'P580' ) local endBoundaries = p.getTimeBoundariesFromQualifier( context.frame, context, claim, 'P582' ) if ( startBoundaries == nil or startBoundaries[ 1 ] <= boundaries[ 1 ] ) and ( endBoundaries == nil or endBoundaries[ 1 ] >= boundaries[ 2 ] ) then table.insert( results, claim.mainsnak ) end end end end if #results > 0 then break end end return results end ---@param context table ---@param propertyId string ---@return table | nil function p.getTimeBoundariesFromProperty( context, propertyId ) local dateClaims = WDS.filter( context.entity.claims, propertyId ) if not dateClaims or #dateClaims == 0 then return nil; end -- only support exact date so far, but need improvment local left = nil local right = nil for _, claim in pairs( dateClaims ) do if not claim.mainsnak then return nil end local boundaries = context.parseTimeBoundariesFromSnak( claim.mainsnak ) if not boundaries then return nil end left = min( left, boundaries[ 1 ] ) right = max( right, boundaries[ 2 ] ) end if not left or not right then return nil end return { left, right } end ---@param context table ---@param propertyIds table<string> ---@return table | nil function p.getTimeBoundariesFromProperties( context, propertyIds ) for _, propertyId in ipairs( propertyIds ) do local result = p.getTimeBoundariesFromProperty( context, propertyId ); if result then return result end end return nil end ---@param context table ---@param statement table ---@param qualifierId string ---@return table | nil function p.getTimeBoundariesFromQualifier( _, context, statement, qualifierId ) -- only support exact date so far, but need improvement local left, right if statement.qualifiers and statement.qualifiers[ qualifierId ] then for _, qualifier in pairs( statement.qualifiers[ qualifierId ] ) do local boundaries = context.parseTimeBoundariesFromSnak( qualifier ) if not boundaries then return nil end left = min( left, boundaries[ 1 ] ) right = max( right, boundaries[ 2 ] ) end end if not left or not right then return nil end return { left, right } end ---@param _ table ---@param context table ---@param statement table ---@param qualifierIds table<string> ---@return table | nil function p.getTimeBoundariesFromQualifiers( _, context, statement, qualifierIds ) if not qualifierIds then qualifierIds = { 'P582', 'P580', 'P585' } end for _, qualifierId in pairs( qualifierIds ) do local result = p.getTimeBoundariesFromQualifier( _, context, statement, qualifierId ) if result then return result end end return nil end ---@type table<string> local getLabelWithLang_DEFAULT_PROPERTIES = { 'P1813', 'P1448', 'P1705' } ---@type table<string> local getLabelWithLang_DEFAULT_SELECTORS = { 'P1813[language:' .. CONTENT_LANGUAGE_CODE .. '][!P282,P282:' .. writingSystemElementId .. '][!P3831,P3831:Q105690470]', 'P1448[language:' .. CONTENT_LANGUAGE_CODE .. '][!P282,P282:' .. writingSystemElementId .. '][!P3831,P3831:Q105690470]', 'P1705[language:' .. CONTENT_LANGUAGE_CODE .. '][!P282,P282:' .. writingSystemElementId .. '][!P3831,P3831:Q105690470]' } ---Функция для получения метки элемента в заданный момент времени. ---@param context table ---@param options table ---@param entityId string ---@param boundaries table ---@param propertyIds table ---@param selectors table<string> ---@return string, string Текстовая метка элемента, язык метки local function getLabelWithLang( context, options, entityId, boundaries, propertyIds, selectors ) if type( entityId ) ~= 'string' then error( 'type of entityId argument expected string, but was ' .. type( entityId ) ); end if not entityId then return nil end local langCode = CONTENT_LANGUAGE_CODE -- name from label local label if options.text and options.text ~= '' then label = options.text else if not propertyIds then propertyIds = getLabelWithLang_DEFAULT_PROPERTIES selectors = getLabelWithLang_DEFAULT_SELECTORS end -- name from properties local results = getPropertyInBoundaries( context, entityId, boundaries, propertyIds, selectors ) for _, result in pairs( results ) do if result.datavalue and result.datavalue.value then if result.datavalue.type == 'monolingualtext' and result.datavalue.value.text then label = result.datavalue.value.text langCode = result.datavalue.value.language break elseif result.datavalue.type == 'string' then label = result.datavalue.value break end end end if not label then label, langCode = mw.wikibase.getLabelWithLang( entityId ) if not langCode then return nil end end end return label, langCode end ---@param context table ---@param options table ---@return string local function formatPropertyDefault( context, options ) if not context then error( 'context not specified' ); end if not options then error( 'options not specified' ); end if not options.entityId then error( 'options.entityId missing' ); end local claims if options.property then -- TODO: Почему тут может не быть property? if options.rank then -- передать настройки ранга из конфига claims = context.selectClaims( options, options.property .. options.rank ) else claims = context.selectClaims( options, options.property ) end end if claims == nil then return '' --TODO error? end -- Обход всех заявлений утверждения и с накоплением оформленных предпочтительных -- заявлений в таблице local formattedClaims = {} for _, claim in pairs( claims ) do local formattedStatement = context.formatStatement( options, claim ) -- здесь может вернуться либо оформленный текст заявления, либо строка ошибки, либо nil if formattedStatement and formattedStatement ~= '' then if not options.plain then formattedStatement = context.wrapStatement( formattedStatement, options.property, claim.id ) end table.insert( formattedClaims, formattedStatement ) end end -- создание текстовой строки со списком оформленых заявлений из таблицы local out = mw.text.listToText( formattedClaims, options.separator, options.conjunction ) if out ~= '' then if options.before then out = options.before .. out end if options.after then out = out .. options.after end end return out end ---Create context ---@param initOptions table ---@return table | nil local function initContext( initOptions ) local context = { entityId = initOptions.entityId, entity = initOptions.entity, extractCategory = extractCategory, formatSnak = formatSnak, formatPropertyDefault = formatPropertyDefault, formatStatementDefault = formatStatementDefault, getPropertyInBoundaries = getPropertyInBoundaries, getTimeBoundariesFromProperty = p.getTimeBoundariesFromProperty, getTimeBoundariesFromProperties = p.getTimeBoundariesFromProperties, getTimeBoundariesFromQualifier = p.getTimeBoundariesFromQualifier, getTimeBoundariesFromQualifiers = p.getTimeBoundariesFromQualifiers, parseTimeFromSnak = p._parseTimeFromSnak, getLabelWithLang = getLabelWithLang, wrapSnak = wrapSnak, wrapStatement = wrapStatement, wrapQualifier = wrapQualifier, } context.cloneOptions = function( options ) local entity = options.entity options.entity = nil local newOptions = mw.clone( options ) options.entity = entity newOptions.entity = entity newOptions.frame = options.frame; -- На склонированном фрейме frame:expandTemplate() return newOptions end context.formatProperty = function( options ) local func = getUserFunction( options, 'property', context.formatPropertyDefault ) return func( context, options ) end context.formatStatement = function( options, statement ) return formatStatement( context, options, statement ) end context.formatSnak = function( options, snak, circumstances ) return formatSnak( context, options, snak, circumstances ) end context.formatRefs = function( options, statement ) return formatRefs( context, options, statement ) end context.parseTimeBoundariesFromSnak = function( snak ) if snak and snak.datavalue and snak.datavalue.value and snak.datavalue.value.time and snak.datavalue.value.precision then return p._parseTimeBoundaries( snak.datavalue.value.time, snak.datavalue.value.precision ) end return nil end context.getSourcingCircumstances = function( statement ) return getSourcingCircumstances( statement ) end context.selectClaims = function( options, propertyId ) return selectClaims( context, options, propertyId ) end return context end ---Функция для оформления утверждений (statement) ---Подробнее о утверждениях см. d:Wikidata:Glossary/ru ---@param options table ---@return string Formatted wikitext. local function formatProperty( options ) -- Получение сущности по идентификатору local entity = getEntityFromId( options.entityId ) if not entity then return -- throwError( 'entity-not-found' ) end -- проверка на присутсвие у сущности заявлений (claim) -- подробнее о заявлениях см. d:Викиданные:Глоссарий if not entity.claims then return '' --TODO error? end -- improve options options.frame = g_frame options.entity = entity options.extends = function( self, newOptions ) return copyTo( newOptions, copyTo( self, {} ) ) end if options.i18n then options.i18n = copyTo( options.i18n, copyTo( getConfig( 'i18n' ), {} ) ) else options.i18n = getConfig( 'i18n' ) end local context = initContext( options ) return context.formatProperty( options ) end ---Функция для оформления одного утверждения (statement) ---@param context table ---@param options table ---@param statement table ---@return string Formatted wikitext. function formatStatement( context, options, statement ) if not statement then error( 'statement is not specified or nil' ) end if not statement.type or statement.type ~= 'statement' then throwError( 'unknown-claim-type' ) end local functionToCall = getUserFunction( options, 'claim', context.formatStatementDefault ) return functionToCall( context, options, statement ) end ---@param statement table ---@return table function getSourcingCircumstances( statement ) if not statement then error( 'statement is not specified' ) end local circumstances = {} if statement.qualifiers and statement.qualifiers.P1480 then for _, qualifier in pairs( statement.qualifiers.P1480 ) do if qualifier and qualifier.datavalue and qualifier.datavalue.type == 'wikibase-entityid' and qualifier.datavalue.value and qualifier.datavalue.value[ 'entity-type'] == 'item' then table.insert( circumstances, qualifier.datavalue.value.id ) end end end return circumstances end ---Функция для оформления одного утверждения (statement) ---@param context table Context. ---@param options table Parameters. ---@param statement table ---@return string Formatted wikitext. function formatStatementDefault( context, options, statement ) if not context then error( 'context is not specified' ) end if not options then error( 'options is not specified' ) end if not statement then error( 'statement is not specified' ) end local circumstances = context.getSourcingCircumstances( statement ) options.qualifiers = statement.qualifiers local result = context.formatSnak( options, statement.mainsnak, circumstances ) if options.qualifier and statement.qualifiers and statement.qualifiers[ options.qualifier ] then local qualifierConfig = getPropertyParams( options.qualifier, nil, {} ) if options.i18n then qualifierConfig.i18n = options.i18n end if qualifierConfig.datatype == 'time' then qualifierConfig.nolinks = true end local qualifierValues = {} for _, qualifierSnak in pairs( statement.qualifiers[ options.qualifier ] ) do local snakValue = context.formatSnak( qualifierConfig, qualifierSnak ) if snakValue and snakValue ~= '' then table.insert( qualifierValues, snakValue ) end end if result and result ~= '' and #qualifierValues then if qualifierConfig.invisible then result = result .. table.concat( qualifierValues, ', ' ) else result = result .. ' (' .. table.concat( qualifierValues, ', ' ) .. ')' end end end if result and result ~= '' and options.references then result = result .. context.formatRefs( options, statement ) end return result end ---Функция для оформления части утверждения (snak) ---Подробнее о snak см. d:Викиданные:Глоссарий ---@param context table Context. ---@param options table Parameters. ---@param snak table ---@param circumstances table ---@return string Formatted wikitext. function formatSnak( context, options, snak, circumstances ) circumstances = circumstances or {} local result if snak.snaktype == 'somevalue' then if options[ 'somevalue' ] and options[ 'somevalue' ] ~= '' then result = options[ 'somevalue' ] else result = options.i18n[ 'somevalue' ] end elseif snak.snaktype == 'novalue' then if options[ 'novalue' ] and options[ 'novalue' ] ~= '' then result = options[ 'novalue' ] else result = options.i18n[ 'novalue' ] end elseif snak.snaktype == 'value' then result = formatDatavalue( context, options, snak.datavalue, snak.datatype ) for _, item in pairs( circumstances ) do if options.i18n[ item ] then result = options.i18n[ item ] .. result end end else throwError( 'unknown-snak-type' ) end if not result or result == '' then return nil end if options.plain then return result end return context.wrapSnak( result, snak.hash ) end ---Функция для оформления объектов-значений с географическими координатами ---@param value string Raw value. ---@param options table Parameters. ---@return string Formatted string. local function formatGlobeCoordinate( value, options ) -- проверка на требование в параметрах вызова на возврат сырого значения if options[ 'subvalue' ] == 'latitude' then -- широты return value[ 'latitude' ] elseif options[ 'subvalue' ] == 'longitude' then -- долготы return value[ 'longitude' ] elseif options[ 'nocoord' ] and options[ 'nocoord' ] ~= '' then -- если передан параметр nocoord, то не выводить координаты -- обычно это делается при использовании нескольких карточек на странице return '' else -- в противном случае формируются параметры для вызова шаблона {{coord}} -- нужно дописать в документации шаблона, что он отсюда вызывается, и что -- любое изменние его парамеров должно быть согласовано с кодом тут local coordModule = require( 'Module:Coordinates' ) local globe = options.globe or '' if globe == '' and value[ 'globe' ] then local globes = require( 'Module:Wikidata/Globes' ) globe = globes[ value[ 'globe' ] ] or '' end local display = 'inline' if options.display and options.display ~= '' then display = options.display elseif ( options.property:upper() == 'P625' ) then display = 'title' end local format = options.format or '' if format == '' then format = 'dms' if value[ 'precision' ] then local precision = value[ 'precision' ] * 60 if precision >= 60 then format = 'd' elseif precision >= 1 then format = 'dm' end end end g_frame.args = { tostring( value[ 'latitude' ] ), tostring( value[ 'longitude' ] ), globe = globe, type = options.type and options.type or '', scale = options.scale and options.scale or '', display = display, format = format, } return coordModule.coord(g_frame) end end ---Функция для оформления объектов-значений с файлами с Викисклада ---@param value string Raw value. ---@param options table Parameters. ---@return string Formatted string. local function formatCommonsMedia( value, options ) local image = value local caption = '' if options[ 'caption' ] and options[ 'caption' ] ~= '' then caption = options[ 'caption' ] end if caption ~= '' then caption = wrapQualifier( caption, 'P2096', { class = 'media-caption', style = 'display:block' } ) end if not string.find( value, '[%[%]%{%}]' ) and not string.find( value, 'UNIQ%-%-imagemap' ) then -- если в value не содержится викикод или imagemap, то викифицируем имя файла -- ищем слово imagemap в строке, потому что вставляется плейсхолдер: [[phab:T28213]] image = '[[File:' .. value .. '|frameless' if options[ 'border' ] and options[ 'border' ] ~= '' then image = image .. '|border' end local size = options[ 'size' ] if size and size ~= '' then -- TODO: check localized pixel names too if not string.match( size, 'px$' ) then size = size .. 'px' end else size = fileDefaultSize end image = image .. '|' .. size if options[ 'alt' ] and options[ 'alt' ] ~= '' then image = image .. '|alt=' .. options[ 'alt' ] end if caption ~= '' then image = image .. '|' .. caption end image = image .. ']]' if caption ~= '' then image = image .. '<br>' .. caption end else image = image .. caption .. getCategoryByCode( 'media-contains-markup' ) end return image end ---Function for render math formulas ---@param value string Value. ---@param options table Parameters. ---@return string Formatted string. local function formatMath( value, options ) return options.frame:extensionTag{ name = 'math', content = value } end ---Функция для оформления внешних идентификаторов ---@param value string ---@param options table ---@return string local function formatExternalId( value, options ) local formatter = options.formatter local propertyId = options.property:upper() if not formatter or formatter == '' then local isGoodFormat = false local wbStatus, formatRegexStatements = pcall( mw.wikibase.getBestStatements, propertyId, 'P1793' ) if wbStatus and formatRegexStatements then for _, statement in pairs( formatRegexStatements ) do if statement.mainsnak.snaktype == 'value' then local pattern = mw.ustring.gsub( statement.mainsnak.datavalue.value, '\\', '%' ) pattern = mw.ustring.gsub( pattern, '{%d+,?%d*}', '+' ) if ( string.find( pattern, '|' ) or string.find( pattern, '%)%?' ) or mw.ustring.match( value, '^' .. pattern .. '$' ) ~= nil ) then isGoodFormat = true break end end end end if isGoodFormat then local formatterStatements wbStatus, formatterStatements = pcall( mw.wikibase.getBestStatements, propertyId, 'P1630' ) if wbStatus and formatterStatements then for _, statement in pairs( formatterStatements ) do if statement.mainsnak.snaktype == 'value' then formatter = statement.mainsnak.datavalue.value break end end end end end if formatter and formatter ~= '' then local encodedValue = mw.ustring.gsub( value, '%%', '%%%%' ) -- ломается, если подставить внутрь другого mw.ustring.gsub local link = mw.ustring.gsub( mw.ustring.gsub( formatter, '$1', encodedValue ), '.', { [ ' ' ] = '%20', [ '+' ] = '%2b', [ '[' ] = '%5B', [ ']' ] = '%5D' } ) local title = options.title if not title or title == '' then title = '$1' end title = mw.ustring.gsub( mw.ustring.gsub( title, '$1', encodedValue ), '.', { [ '[' ] = '(', [ ']' ] = ')' } ) return '[' .. link .. ' ' .. title .. ']' end return value end ---Функция для оформления числовых значений ---@param value table Объект-значение ---@param options table Таблица параметров ---@return string Оформленный текст local function formatQuantity( value, options ) -- диапазон значений local amount = string.gsub( value.amount, '^%+', '' ) local lang = mw.language.getContentLanguage() local langCode = lang:getCode() local function formatNum( number, sigfig ) local multiplier = '' if options.countByThousands then local powers = options.i18n.thousandPowers local pos = 1 while math.abs( number ) >= 1000 and pos < #powers do number = number / 1000 pos = pos + 1 end multiplier = powers[ pos ] if math.abs( number ) >= 100 then sigfig = sigfig or 0 elseif math.abs( number ) >= 10 then sigfig = sigfig or 1 else sigfig = sigfig or 2 end else sigfig = sigfig or 12 -- округление до 12 знаков после запятой, на 13-м возникает ошибка в точности end local iMultiplier = 10^sigfig number = math.floor( number * iMultiplier + 0.5 ) / iMultiplier return string.gsub( lang:formatNum( number ), '^-', '−' ) .. multiplier end local out = formatNum( tonumber( amount ) ) if value.upperBound then local diff = tonumber( value.upperBound ) - tonumber( amount ) if diff > 0 then -- временная провека, пока у большинства значений не будет убрано ±0 -- Пробуем понять до какого знака округлять local integer, dot, decimals, _ = value.upperBound:match( '^+?-?(%d*)(%.?)(%d*)(.*)' ) local precision if dot == '' then precision = -integer:match( '0*$' ):len() else precision = #decimals end local bound = formatNum( diff, precision ) if string.match( bound, 'E%-(%d+)' ) then -- если в экспоненциальном формате local digits = tonumber( string.match( bound, 'E%-(%d+)' ) ) - 2 bound = formatNum( diff * 10 ^ digits, precision ) bound = string.sub( bound, 0, 2 ) .. string.rep( '0', digits ) .. string.sub( bound, -string.len( bound ) + 2 ) end out = out .. ' ± ' .. bound end end if options.unit and options.unit ~= '' then if options.unit ~= '-' then out = out .. ' ' .. options.unit end elseif value.unit and string.match( value.unit, 'http://www.wikidata.org/entity/' ) then local unitEntityId = string.gsub( value.unit, 'http://www.wikidata.org/entity/', '' ) if unitEntityId ~= 'undefined' then local wbStatus, unitEntity = pcall( mw.wikibase.getEntity, unitEntityId ) if wbStatus == true and unitEntity then if unitEntity.claims.P2370 and unitEntity.claims.P2370[ 1 ].mainsnak.snaktype == 'value' and not value.upperBound and options.siConversion == true then local conversionToSiUnit = string.gsub( unitEntity.claims.P2370[ 1 ].mainsnak.datavalue.value.amount, '^%+', '' ) if math.floor( math.log10( conversionToSiUnit ) ) ~= math.log10( conversionToSiUnit ) then -- Если не степени десятки (переводить сантиметры в метры не надо!) local outValue = tonumber( amount ) * conversionToSiUnit if outValue > 0 then -- Пробуем понять до какого знака округлять local integer, dot, decimals, _ = amount:match( '^(%d*)(%.?)(%d*)(.*)' ) local precision if dot == '' then precision = -integer:match( '0*$' ):len() else precision = #decimals end local adjust = math.log10( math.abs( conversionToSiUnit ) ) + math.log10( 2 ) local minPrecision = 1 - math.floor( math.log10( outValue ) + 2e-14 ) out = formatNum( outValue, math.max( math.floor( precision + adjust ), minPrecision ) ) else out = formatNum( outValue, 0 ) end unitEntityId = string.gsub( unitEntity.claims.P2370[ 1 ].mainsnak.datavalue.value.unit, 'http://www.wikidata.org/entity/', '' ) wbStatus, unitEntity = pcall( mw.wikibase.getEntity, unitEntityId ) end end local label = getLabelWithLang( context, options, unitEntity.id, nil, { "P5061", "P558", "P558" }, { 'P5061[language:' .. langCode .. ']', 'P558[P282:' .. writingSystemElementId .. ', P407:' .. langElementId .. ']', 'P558[!P282][!P407]' } ) out = out .. ' ' .. label end end end return out end ---Функция для оформления URL ---@param context table ---@param options table ---@param value string local function formatUrlValue( context, options, value ) if not options.length or options.length == '' then options.length = 25 end local moduleUrl = require( 'Module:URL' ) return moduleUrl.formatUrlSingle( context, options, value ) end local DATATYPE_CACHE = {} ---Get property datatype by ID. ---@param propertyId string Property ID, e.g. 'P123'. ---@return string Property datatype, e.g. 'commonsMedia', 'time' or 'url'. local function getPropertyDatatype( propertyId ) if not propertyId or not string.match( propertyId, '^P%d+$' ) then return nil end local cached = DATATYPE_CACHE[ propertyId ] if cached ~= nil then return cached end local wbStatus, propertyEntity = pcall( mw.wikibase.getEntity, propertyId ) if wbStatus ~= true or not propertyEntity then return nil end mw.log("Loaded datatype " .. propertyEntity.datatype .. " of " .. propertyId .. ' from wikidata, consider passing datatype argument to formatProperty call or to Wikidata/config' ) DATATYPE_CACHE[ propertyId ] = propertyEntity.datatype return propertyEntity.datatype end ---@param datavalue table ---@return function local function getPlainValueFunction( datavalue, _ ) if datavalue.type == 'wikibase-entityid' then return function( _, _, value ) return getEntityIdFromValue( value ) end elseif datavalue.type == 'string' then return function( _, _, value ) return value end elseif datavalue.type == 'monolingualtext' then return function( _, _, value ) return value.text end elseif datavalue.type == 'globecoordinate' then return function( _, _, value ) return value.latitude .. ',' .. value.longitude end elseif datavalue.type == 'quantity' then return function( _, _, value ) return value.amount end elseif datavalue.type == 'time' then return function( _, _, value ) return value.time end end throwError( 'unknown-datavalue-type' ) end ---@param datavalue table ---@param datatype string ---@return function local function getDefaultValueFunction( datavalue, datatype ) -- вызов обработчиков по умолчанию для известных типов значений if datavalue.type == 'wikibase-entityid' then -- Entity ID return function( context, options, value ) return formatEntityId( context, options, getEntityIdFromValue( value ) ) end elseif datavalue.type == 'string' then -- String if datatype and datatype == 'commonsMedia' then -- Media return function( _, options, value ) return formatCommonsMedia( value, options ) end elseif datatype and datatype == 'external-id' then -- External ID return function( _, options, value ) return formatExternalId( value, options ) end elseif datatype and datatype == 'math' then -- Math formula return function( _, options, value ) return formatMath( value, options ) end elseif datatype and datatype == 'url' then -- URL return formatUrlValue end return function( _, _, value ) return value end elseif datavalue.type == 'monolingualtext' then -- моноязычный текст (строка с указанием языка) return function( _, options, value ) if options.monolingualLangTemplate == 'lang' then if value.language == CONTENT_LANGUAGE_CODE then return value.text end return options.frame:expandTemplate{ title = 'lang-' .. value.language, args = { value.text } } elseif options.monolingualLangTemplate == 'ref' then return '<span class="lang" lang="' .. value.language .. '">' .. value.text .. '</span>' .. options.frame:expandTemplate{ title = 'ref-' .. value.language } else return '<span class="lang" lang="' .. value.language .. '">' .. value.text .. '</span>' end end elseif datavalue.type == 'globecoordinate' then -- географические координаты return function( _, options, value ) return formatGlobeCoordinate( value, options ) end elseif datavalue.type == 'quantity' then return function( _, options, value ) return formatQuantity( value, options ) end elseif datavalue.type == 'time' then return function( context, options, value ) local moduleDate = require( 'Module:Wikidata/date' ) return moduleDate.formatDate( context, options, value ) end end -- во всех стальных случаях возвращаем ошибку throwError( 'unknown-datavalue-type' ) end ---Функция для оформления значений (value) ---Подробнее о значениях см. d:Wikidata:Glossary/ru ---@param context table ---@param options table ---@param datavalue table ---@param datatype string ---@return string Оформленный текст function formatDatavalue( context, options, datavalue, datatype ) if not context then error( 'context not specified' ); end if not options then error( 'options not specified' ); end if not datavalue then error( 'datavalue not specified' ); end if not datavalue.value then error( 'datavalue.value is missing' ); end -- проверка на указание специализированных обработчиков в параметрах, -- переданных при вызове if options.plain then context.formatValueDefault = getPlainValueFunction( datavalue, datatype ) else context.formatValueDefault = getDefaultValueFunction( datavalue, datatype ) end local functionToCall = getUserFunction( options, 'value', context.formatValueDefault ) return functionToCall( context, options, datavalue.value ) end local DEFAULT_BOUNDARIES = { os.time() * 1000, os.time() * 1000} ---Функция для оформления идентификатора сущности ---@param context table ---@param options table ---@param entityId string ---@return string Оформленный текст function formatEntityId( context, options, entityId ) -- получение локализованного названия local boundaries if options.qualifiers then boundaries = p.getTimeBoundariesFromQualifiers( context.frame, context, { qualifiers = options.qualifiers } ) end if not boundaries then boundaries = DEFAULT_BOUNDARIES end local label, labelLanguageCode = getLabelWithLang( context, options, entityId, boundaries ) -- определение соответствующей показываемому элементу категории local category = context.extractCategory( options, { id = entityId } ) -- получение ссылки по идентификатору local link = mw.wikibase.sitelink( entityId ) if link then -- ссылка на категорию, а не добавление страницы в неё if mw.ustring.match( link, '^' .. mw.site.namespaces[ 14 ].name .. ':' ) then link = ':' .. link end if label and not options.rawArticle then if labelLanguageCode ~= CONTENT_LANGUAGE_CODE then label = '<span lang="' .. label .. '">' .. label .. '</span>' end local a = '[[' .. link .. '|' .. label .. ']]' if CONTENT_LANGUAGE_CODE ~= labelLanguageCode and 'mul' ~= labelLanguageCode then a = a .. getCategoryByCode( 'links-to-entities-with-missing-local-language-label' ) end return a .. category else return '[[' .. link .. ']]' .. category end end if label then -- TODO: возможно, лучше просто mw.wikibase.getLabel(entityId) -- красная ссылка -- TODO: разобраться, почему не всегда есть options.frame local moduleRedLink = require( 'Module:Wikidata/redLink' ) local title = mw.title.new( label ) if title and not title.exists and options.frame then local rawLabel = mw.wikibase.getLabel(entityId) or label -- без |text= и boundaries; or label - костыль local redLink = moduleRedLink.formatRedLinkWithInfobox(rawLabel, label, entityId) if CONTENT_LANGUAGE_CODE ~= labelLanguageCode and 'mul' ~= labelLanguageCode then redLink = '<span lang="' .. labelLanguageCode .. '">' .. redLink .. '</span>' .. getCategoryByCode( 'links-to-entities-with-missing-local-language-label' ) end return redLink .. category end -- TODO: перенести до проверки на существование статьи local addWdLink = false if ( not options.format or options.format ~= 'text' ) and entityId ~= 'Q6581072' and entityId ~= 'Q6581097' -- TODO: переписать на format=text then addWdLink = true end -- одноимённая статья уже существует - выводится текст и ссылка на ВД return moduleRedLink.formatText(label, entityId, addWdLink) .. category end -- сообщение об отсутвии локализованного названия -- not good, but better than nothing return '[[:d:' .. entityId .. '|' .. entityId .. ']]<span style="border-bottom: 1px dotted; cursor: help; white-space: nowrap" title="В Викиданных нет русской подписи к элементу. Вы можете помочь, указав русский вариант подписи.">?</span>' .. getCategoryByCode( 'links-to-entities-with-missing-label' ) .. category end ---Функция для оформления утверждений (statement) ---Подробнее о утверждениях см. d:Wikidata:Glossary/ru ---@deprecated Use p.formatProperty() instead ---@param frame table ---@return string Строка оформленного текста, предназначенная для отображения в статье function p.formatStatements( frame ) return p.formatProperty( frame ) end ---Получение параметров, которые обычно используются для вывода свойства. ---@param propertyId string ---@param datatype string ---@param params table function getPropertyParams( propertyId, datatype, params ) local config = getConfig() -- Различные уровни настройки параметров, по убыванию приоритета local propertyParams = {} -- 1. Параметры, указанные явно при вызове if params then for key, value in pairs( params ) do if value ~= '' then propertyParams[ key ] = value end end end if toBoolean( propertyParams.plain, false ) then propertyParams.separator = propertyParams.separator or ', ' propertyParams.conjunction = propertyParams.conjunction or ', ' else -- 2. Настройки конкретного параметра if config.properties and config.properties[ propertyId ] then for key, value in pairs( config.properties[ propertyId ] ) do if propertyParams[ key ] == nil then propertyParams[ key ] = value end end end -- 3. Указанный пресет настроек if propertyParams.preset and config.presets and config.presets[ propertyParams.preset ] then for key, value in pairs( config.presets[ propertyParams.preset ] ) do if propertyParams[ key ] == nil then propertyParams[ key ] = value end end end datatype = datatype or params.datatype or propertyParams.datatype or getPropertyDatatype( propertyId ) if propertyParams.datatype == nil then propertyParams.datatype = datatype end -- 4. Настройки для типа данных if datatype and config.datatypes and config.datatypes[ datatype ] then for key, value in pairs( config.datatypes[ datatype ] ) do if propertyParams[ key ] == nil then propertyParams[ key ] = value end end end -- 5. Общие настройки для всех свойств if config.global then for key, value in pairs( config.global ) do if propertyParams[ key ] == nil then propertyParams[ key ] = value end end end end return propertyParams end ---Функция для оформления утверждений (statement) ---Подробнее о утверждениях см. d:Wikidata:Glossary/ru ---@param frame table ---@return string Строка оформленного текста, предназначенная для отображения в статье function p.formatProperty( frame ) local args = copyTo( frame.args, {} ) -- проверка на отсутствие обязательного параметра property if not args.property then throwError( 'property-param-not-provided' ) end local override local propertyId = mw.language.getContentLanguage():ucfirst( string.gsub( args.property, '([^Pp0-9].*)$', function(w) if string.sub( w, 1, 1 ) == '~' then override = w end return '' end ) ) if override then args[ override:match( '[,~]([^=]*)=' ) ] = override:match( '=(.*)' ) args.property = propertyId end -- проброс всех параметров из шаблона {wikidata} и параметра from откуда угодно local p_frame = frame while p_frame do if p_frame:getTitle() == mw.site.namespaces[ 10 ].name .. ':Wikidata' then copyTo( p_frame.args, args, true ) end if p_frame.args and p_frame.args.from and p_frame.args.from ~= '' then args.entityId = p_frame.args.from else args.entityId = mw.wikibase.getEntityIdForCurrentPage() end p_frame = p_frame:getParent() end args = getPropertyParams( propertyId, nil, args ) local datatype = args.datatype -- перевод итоговых значений флагов в true/false и добавление значений -- по умолчанию только в том случае, если они нигде не были указаны ранее args.plain = toBoolean( args.plain, false ) args.nocat = not args.plain and toBoolean( args.nocat, false ) args.references = not args.plain and toBoolean( args.references, true ) -- если значение передано в параметрах вызова то выводим только его if args.value and args.value ~= '' then -- специальное значение для скрытия Викиданных if args.value == '-' then return '' end local value = args.value -- опция, запрещающая оформление значения, поэтому никак не трогаем if args.plain then return value end local context = initContext( args ) -- обработчики по типу значения local wrapperExtraArgs = {} if args[ 'value-module' ] and args[ 'value-function' ] and not string.find( value, '[%[%]%{%}]' ) then local func = getUserFunction( args, 'value' ) value = func( context, args, value ) elseif datatype == 'commonsMedia' then value = formatCommonsMedia( value, args ) elseif datatype == 'external-id' and not string.find( value, '[%[%]%{%}]' ) then wrapperExtraArgs[ 'data-wikidata-external-id' ] = mw.text.killMarkers( value ) value = formatExternalId( value, args ) --elseif datatype == 'math' then -- args.frame = frame -- костыль: в formatMath нужно frame:extensionTag -- value = formatMath( value, args ) elseif datatype == 'url' then value = formatUrlValue( context, args, value ) end -- оборачиваем в тег для JS-функций if string.match( propertyId, '^P%d+$' ) then value = mw.text.trim( value ) -- временная штрафная категория для исправления табличных вставок local allowTables = getPropertyParams( propertyId, nil, {} ).allowTables if not allowTables and string.match( value, '<t[dhr][ >]' ) -- and not string.match( value, '<table[ >]' ) -- and not string.match( value, '^%{%|' ) then value = value .. getCategoryByCode( 'value-contains-table', propertyId ) else value = wrapStatement( value, propertyId, nil, wrapperExtraArgs ) end end return value end -- ability to disable loading Wikidata if args.entityId == '-' then return '' end g_frame = frame -- после проверки всех аргументов -- вызов функции оформления для свойства (набора утверждений) return formatProperty( args ) end ---Функция проверки на присутствие источника в списке нерекомендованных. ---@param snaks table ---@return boolean local function isReferenceDeprecated( snaks ) if not snaks then return false end if snaks.P248 and snaks.P248[ 1 ] and snaks.P248[ 1 ].datavalue and snaks.P248[ 1 ].datavalue.value.id then local entityId = snaks.P248[ 1 ].datavalue.value.id if getConfig( 'deprecatedSources', entityId ) then return true end elseif snaks.P1433 and snaks.P1433[ 1 ] and snaks.P1433[ 1 ].datavalue and snaks.P1433[ 1 ].datavalue.value.id then local entityId = snaks.P1433[ 1 ].datavalue.value.id if getConfig( 'deprecatedSources', entityId ) then return true end end return false end ---Функция оформления ссылок на источники (reference) ---Подробнее о ссылках на источники см. d:Wikidata:Glossary/ru --- ---Экспортируется в качестве зарезервированной точки для вызова из функций-расширения вида claim-module/claim-function через context ---Вызов из других модулей напрямую осуществляться не должен (используйте frame:expandTemplate вместе с одним из специлизированных шаблонов вывода значения свойства). ---@param context table ---@param options table ---@param statement table ---@return string Оформленные примечания для отображения в статье function formatRefs( context, options, statement ) if not context then error( 'context not specified' ); end if not options then error( 'options not specified' ); end if not options.entityId then error( 'options.entityId missing' ); end if not statement then error( 'statement not specified' ); end if not outputReferences then return '' end ---@type string[] local references = {} if statement.references then local hasNotDeprecated = false local displayCount = 0 for _, reference in pairs( statement.references ) do if not isReferenceDeprecated( reference.snaks ) then hasNotDeprecated = true end end for _, reference in pairs( statement.references ) do local display = true if hasNotDeprecated then if isReferenceDeprecated( reference.snaks ) then display = false end end if displayCount >= 2 then if options.entityId and options.property then local propertyId = mw.ustring.match( options.property, '^[Pp][0-9]+' ) -- TODO: обрабатывать не тут, а раньше local moreReferences = '<sup>[[d:' .. options.entityId .. '#' .. string.upper( propertyId ) .. '|[…]]]</sup>' table.insert( references, moreReferences ) end break end if display == true then ---@type string local refText = moduleSources.renderReference( g_frame, options.entityId, reference ) if refText and refText ~= '' then table.insert( references, refText ) displayCount = displayCount + 1 end end end end return table.concat( references ) end return p 4558f762f30c6ebfb9f5333dbd7ebda83c6873f2 Модуль:Sources 828 32 62 61 2025-01-25T21:00:17Z Vallenland 2 1 версия импортирована Scribunto text/plain ---@alias args table ---@alias frame { args: args, extensionTag: function, newChild: ( fun( args: args ): frame ) } ---@alias source { publication: source, [string]: any } ---@alias value: string | { id: string } ---@alias snak { datatype: string, snaktype: string, datavalue: { type: string, value: value } } ---@alias snaks table<string, table<number, snak>> ---@alias statement { mainsnak: snak, rank: string, qualifiers: snaks } ---@alias statements table<string, table<number, statement>> ---@alias map { name: string, ids: string[] }[]> ---@type table local p = {} ---@type table<string, string> local NORMATIVE_DOCUMENTS = { Q20754888 = 'Закон Российской Федерации', Q20754884 = 'Закон РСФСР', Q20873831 = 'Распоряжение Президента Российской Федерации', Q20873834 = 'Указ исполняющего обязанности Президента Российской Федерации', Q2061228 = 'Указ Президента Российской Федерации', } ---@type table<string, string> local LANG_CACHE = { Q150 = 'fr', Q188 = 'de', Q1321 = 'es', Q1860 = 'en', Q652 = 'it', Q7737 = 'ru', Q8798 = 'uk', } ---@type map local PROPERTY_MAP = { { name = 'sourceId', ids = { 'P248', 'P805' } }, { name = 'lang', ids = { 'P407', 'P364' } }, { name = 'author', ids = { 'P50', 'P2093' } }, { name = 'part', ids = { 'P958', 'P1810' } }, { name = 'title', ids = { 'P1476' } }, { name = 'subtitle', ids = { 'P1680' } }, { name = 'url', ids = { 'P953', 'P1065', 'P854', 'P973', 'P2699', 'P888' } }, { name = 'editor', ids = { 'P98' } }, { name = 'translator', ids = { 'P655' } }, { name = 'publication-id', ids = { 'P1433' } }, { name = 'edition', ids = { 'P393' } }, { name = 'publisher', ids = { 'P123' } }, { name = 'place', ids = { 'P291' } }, { name = 'volume', ids = { 'P478' } }, { name = 'issue', ids = { 'P433' } }, { name = 'dateOfCreation', ids = { 'P571' } }, { name = 'dateOfPublication', ids = { 'P577' } }, { name = 'pages', ids = { 'P304' } }, { name = 'numberOfPages', ids = { 'P1104' } }, { name = 'tirage', ids = { 'P1092' } }, { name = 'isbn', ids = { 'P212', 'P957' } }, { name = 'issn', ids = { 'P236' } }, -- { name = 'accessdate', ids = { 'P813' } }, -- disable, creates duplicate references { name = 'docNumber', ids = { 'P1545' } }, { name = 'type', ids = { 'P31' } }, { name = 'arxiv', ids = { 'P818' } }, { name = 'doi', ids = { 'P356' } }, { name = 'pmid', ids = { 'P698' } }, } -- table.insert( PROPERTY_MAP.url, 'P856' ) -- only as qualifier ---@type map local PUBLICATION_PROPERTY_MAP = mw.clone( PROPERTY_MAP ) ---@type string[] local monthGen = { 'января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря' } ---@type string local i18nDefaultLanguage = mw.language.getContentLanguage():getCode() p.i18nDefaultLanguage = i18nDefaultLanguage ---@type string local i18nEtAlDefault = ' et al.' ---@type table<string, string> local i18nEtAl = { ru = ' и др.', uk = ' та ін.', } ---@type table<string, string> local i18nEditors = { fr = '', de = 'Hrsg.: ', es = '', en = '', it = '', ru = 'под ред. ', uk = 'за ред. ', } ---@type table<string, string> local i18nTranslators = { fr = '', de = '', es = '', en = '', it = '', ru = 'пер. ', uk = 'пер. ', } ---@type table<string, string> local i18nVolume = { de = 'Vol.', fr = 'Vol.', es = 'Vol.', en = 'Vol.', it = 'Vol.', ru = 'Т.', uk = 'Т.', } ---@type table<string, string> local i18nIssue = { en = 'Iss.', ru = 'вып.', uk = 'вип.', } ---@type table<string, string> local i18nPages = { fr = 'P.', de = 'S.', es = 'P.', en = 'P.', it = 'P.', ru = 'С.', uk = 'С.', } ---@type table<string, string> local i18nNumberOfPages = { en = 'p.', ru = 'с.', } ---@type table<string, string> local i18nTirage = { en = 'ed. size: %d', ru = '%d экз.', } ---@param args args ---@return source local function getFilledArgs( args ) ---@type source local data = {} for key, value in pairs( args ) do if mw.text.trim( value ) ~= '' then if key == 1 then key = 'sourceId' end data[ key ] = mw.text.trim( value ) end end return data end ---Returns formatted pair {Family name(s), First name(s)} ---@param fullName string ---@return table<number, string> local function tokenizeName( fullName ) local space = '%s+' -- matches single or more spacing character local name = "(%a[%a%-']*)%.?" -- matches single name, have to start with letter, can contain apostrophe and hyphen, may end with dot local surname = "(%a[%a%-']*)" -- same as name, but can't end with dot local surnamePrefixes = { 'ван', 'van', 'де', 'de' } local nm, nm2, srn, srn2, pref fullName = ' ' .. fullName .. ' ' fullName = mw.ustring.gsub( fullName, ' оглы ', ' ' ) fullName = mw.text.trim( fullName ) -- Surname, Name local pattern = '^' .. surname .. ',' .. space .. name .. '$' srn, nm = mw.ustring.match( fullName, pattern ) if srn then return { srn, mw.ustring.sub( nm, 1, 1 ) .. '.' } end -- Surname, Name prefix for _, surnamePrefix in pairs( surnamePrefixes ) do pattern = '^' .. surname .. ',' .. space .. name .. space .. '(' .. surnamePrefix .. ')' .. '$' srn, nm, pref = mw.ustring.match( fullName, pattern ) if srn then return { mw.ustring.sub( pref ) .. ' ' .. srn, mw.ustring.sub( nm, 1, 1 ) .. '.' } end end -- Surname, Name Name pattern = '^' .. surname .. ',' .. space .. name .. space .. name .. '$' srn, nm, nm2 = mw.ustring.match( fullName, pattern ) if srn then return { srn, mw.ustring.sub( nm, 1, 1 ) .. '.&nbsp;' .. mw.ustring.sub( nm2, 1, 1 ) .. '.' } end -- Surname Surname, Name pattern = '^' .. surname .. space .. surname .. ',' .. space .. name .. '$' srn, srn2, nm = mw.ustring.match( fullName, pattern ) if srn then return { srn .. '&nbsp;' .. srn2, mw.ustring.sub( nm, 1, 1 ) .. '.' } end -- Name Name Surname pattern = '^' .. name .. space .. name .. space .. surname .. '$' nm, nm2, srn = mw.ustring.match( fullName, pattern ) if srn then return { srn, mw.ustring.sub( nm, 1, 1 ) .. '.&nbsp;' .. mw.ustring.sub( nm2, 1, 1 ) .. '.' } end -- Name Name prefix Surname for _, surnamePrefix in pairs( surnamePrefixes ) do pattern = '^' .. name .. space .. name .. space .. '(' .. surnamePrefix .. ')' .. space .. surname .. '$' nm, nm2, pref, srn = mw.ustring.match( fullName, pattern ) if srn then return { mw.ustring.sub( pref ) .. ' ' .. srn, mw.ustring.sub( nm, 1, 1 ) .. '.&nbsp;' .. mw.ustring.sub( nm2, 1, 1 ) .. '.' } end end -- Surname, Name Name prefix for _, surnamePrefix in pairs( surnamePrefixes ) do pattern = '^' .. surname .. ',' .. space .. name .. space .. name .. space .. '(' .. surnamePrefix .. ')' .. '$' srn, nm, nm2, pref = mw.ustring.match( fullName, pattern ) if srn then return { mw.ustring.sub( pref ) .. ' ' .. srn, mw.ustring.sub( nm, 1, 1 ) .. '.&nbsp;' .. mw.ustring.sub( nm2, 1, 1 ) .. '.' } end end -- Name{1,4} Surname for k = 1, 4 do pattern = '^' .. string.rep( name .. space, k ) .. surname .. '$' ---@type string[] local matched = { mw.ustring.match( fullName, pattern ) } if #matched ~= 0 then for j = 1, k do matched[ j ] = mw.ustring.sub( matched[ j ], 1, 1 ) end return { matched[ k + 1 ], table.concat( matched, '.&nbsp;', 1, k ) .. '.' } end end -- Surname Name{1,4} for k = 1, 4 do pattern = '^' .. surname .. string.rep( space .. name, k ) .. '$' ---@type string[] local matched = { mw.ustring.match( fullName, pattern ) } if #matched ~= 0 then for j = 2, k + 1 do matched[ j ] = mw.ustring.sub( matched[ j ], 1, 1 ) end return { matched[ 1 ], table.concat( matched, '.&nbsp;', 2, k + 1 ) .. '.' } end end return { fullName } end ---@param fullName string | nil ---@return string | nil local function personNameToAuthorName( fullName ) if not fullName then return nil end local tokenized = tokenizeName( fullName ) if #tokenized == 1 then return tokenized[ 1 ] end return tokenized[ 1 ] .. '&nbsp;' .. tokenized[ 2 ] end ---@param fullName string | nil ---@return string | nil local function personNameToResponsibleName( fullName ) if not fullName then return nil end local tokenized = tokenizeName( fullName ) if #tokenized == 1 then return tokenized[ 1 ] end return tokenized[ 2 ] .. '&nbsp;' .. tokenized[ 1 ] end ---@alias options { separator: string, conjunction: string, format: ( fun( data: string ): string ), nolinks: boolean, preferids: boolean, short: boolean } ---@type options local options_commas = { separator = ', ', conjunction = ', ', format = function( data ) return data end, nolinks = false, preferids = false, short = false, } ---@type options local options_commas_short = mw.clone( options_commas ) options_commas_short.short = true ---@type options local options_commas_it_short = mw.clone( options_commas_short ) options_commas_it_short.format = function( data ) return "''" .. data .. "''" end ---@type options local options_commas_nolinks = mw.clone( options_commas ) options_commas_nolinks.nolinks = true ---@type options local options_citetypes = { separator = ' ', conjunction = ' ', format = function( data ) return 'citetype_' .. data end, nolinks = true , preferids = true, short = false, } ---@type options local options_commas_authors = mw.clone( options_commas ) options_commas_authors.format = personNameToAuthorName ---@type options local options_commas_responsible = mw.clone( options_commas ) options_commas_responsible.format = personNameToResponsibleName ---@type options local options_ids = { separator = '; ', conjunction = '; ', format = function( id ) return id end, nolinks = true, preferids = false, short = false, } ---@type options local options_arxiv = mw.clone( options_ids ) options_arxiv.format = function( id ) return '[https://arxiv.org/abs/' .. id .. ' arXiv:' .. id .. ']' end ---@type options local options_doi = mw.clone( options_ids ) options_doi.format = function( doi ) return '[https://dx.doi.org/' .. doi .. ' doi:' .. doi .. ']' end ---@type options local options_issn = mw.clone( options_ids ) options_issn.format = function( issn ) return '[https://www.worldcat.org/issn/' .. issn .. ' ' .. issn .. ']' end ---@type options local options_pmid = mw.clone( options_ids ) options_pmid.format = function( pmid ) return '[https://www.ncbi.nlm.nih.gov/pubmed/?term=' .. pmid .. ' PMID:' .. pmid .. ']' end ---@param str string | nil ---@return boolean local function isEmpty( str ) return not str or #str == 0 end ---@param allQualifiers snaks ---@param qualifierPropertyId string ---@return string | nil local function getSingleStringQualifierValue( allQualifiers, qualifierPropertyId ) if not allQualifiers or not allQualifiers[ qualifierPropertyId ] then return nil end ---@type table<number, snak> local propertyQualifiers = allQualifiers[ qualifierPropertyId ] for _, qualifier in pairs( propertyQualifiers ) do if ( qualifier and qualifier.datatype == 'string' and qualifier.datavalue and qualifier.datavalue.type == 'string' and qualifier.datavalue.value ~= '' ) then return qualifier.datavalue.value end end return nil end ---@param data table ---@param resultProperty string ---@return void local function appendImpl_toTable( data, resultProperty ) if not data[ resultProperty ] then data[ resultProperty ] = {} elseif ( type( data[ resultProperty ] ) == 'string' or ( type( data[ resultProperty ] ) == 'table' and type( data[ resultProperty ].id ) == 'string' ) ) then data[ resultProperty ] = { data[ resultProperty ] } end end ---@param datavalue table ---@param qualifiers snaks ---@param data table ---@param propertyName string ---@param options table local function appendImpl( datavalue, qualifiers, data, propertyName, options ) data[ propertyName ] = data[ propertyName ] or {} if propertyName == 'issn' then table.insert( data[ propertyName ], datavalue.value ) elseif propertyName == 'url' or datavalue.type == 'url' then local value = datavalue.value if options.format then value = options.format( value ) end appendImpl_toTable( data, propertyName ) table.insert( data[ propertyName ], value ) elseif datavalue.type == 'string' then local value = getSingleStringQualifierValue( qualifiers, 'P1932' ) if not value then value = getSingleStringQualifierValue( qualifiers, 'P1810' ) end if not value then value = datavalue.value if options.format then value = options.format( value ) end end appendImpl_toTable(data, propertyName) local pos = getSingleStringQualifierValue( qualifiers, 'P1545' ) if pos then table.insert( data[ propertyName ], tonumber(pos), value ) else table.insert( data[ propertyName ], value ) end elseif datavalue.type == 'monolingualtext' then local value = datavalue.value.text if options.format then value = options.format( value ) end appendImpl_toTable( data, propertyName ) table.insert( data[ propertyName ], value ) elseif datavalue.type == 'quantity' then local value = datavalue.value.amount if ( mw.ustring.sub( value , 1, 1 ) == '+' ) then value = mw.ustring.sub( value , 2 ) end if options.format then value = options.format( value ) end appendImpl_toTable( data, propertyName ) table.insert( data[ propertyName ], value ) elseif datavalue.type == 'wikibase-entityid' then local pos = getSingleStringQualifierValue( qualifiers, 'P1545' ) local value = datavalue.value appendImpl_toTable(data, propertyName) local label = getSingleStringQualifierValue( qualifiers, 'P1932' ) if not label then label = getSingleStringQualifierValue( qualifiers, 'P1810' ) end local toInsert = { id = value.id, label = label } if pos and tonumber( pos ) then table.insert( data[ propertyName ], tonumber( pos ), toInsert ) else table.insert( data[ propertyName ], toInsert ) end elseif datavalue.type == 'time' then local value = datavalue.value if options.format then value = options.format( value ) end appendImpl_toTable( data, propertyName ) table.insert( data[ propertyName ], tostring( value.time ) ) end end ---@param entityId string ---@param propertyId string ---@return table<number, statement> local function getAllStatements( entityId, propertyId ) ---@type boolean, table<number, statement> local wdStatus, statements = pcall( mw.wikibase.getAllStatements, entityId, propertyId ) if wdStatus and statements then return statements end return {} end ---@param entityId string ---@param propertyId string ---@return table<number, statement> local function getBestStatements( entityId, propertyId ) ---@type boolean, table<number, statement> local wdStatus, statements = pcall( mw.wikibase.getBestStatements, entityId, propertyId ) if wdStatus and statements then return statements end return {} end ---@param entityId string ---@param projectToCheck string? ---@return string | nil local function getSitelink( entityId, projectToCheck ) ---@type boolean, string local wbStatus, sitelink if projectToCheck then wbStatus, sitelink = pcall( mw.wikibase.getSitelink, entityId, projectToCheck ) else wbStatus, sitelink = pcall( mw.wikibase.getSitelink, entityId ) end if not wbStatus then return nil end return sitelink end ---@param args any[] ---@return any | nil local function coalesce( args ) for _, arg in pairs( args ) do if not isEmpty( arg ) then return arg end end return nil end ---@param value any ---@return string | nil local function getSingle( value ) if type( value ) == 'string' then return tostring( value ) elseif type( value ) == 'table' then if value.id then return tostring( value.id ) end for _, tableValue in pairs( value ) do return getSingle( tableValue ) end end return nil end ---@param langEntityId string ---@return string | nil local function getLangCode( langEntityId ) if not langEntityId then return nil end langEntityId = getSingle( langEntityId ) if not string.match( langEntityId, '^Q%d+$' ) then return langEntityId end local cached = LANG_CACHE[ langEntityId ] if cached then if cached == '' then return nil end return cached end local claims = getBestStatements( langEntityId, 'P424' ) for _, claim in pairs( claims ) do if claim and claim.mainsnak and claim.mainsnak.datavalue and claim.mainsnak.datavalue.value then LANG_CACHE[ langEntityId ] = claim.mainsnak.datavalue.value return claim.mainsnak.datavalue.value end end LANG_CACHE[ langEntityId ] = '' return nil end ---@param entityId string ---@param propertyId string ---@param data source ---@param propertyName string ---@param options table? ---@return void local function appendEntitySnaks( entityId, propertyId, data, propertyName, options ) options = options or {} -- do not populate twice if data[ propertyName ] and ( propertyName ~= 'author' or data[ propertyId ] ) then return end local statements = getBestStatements( entityId, propertyId ) if propertyName == 'author' then data[ propertyId ] = true end local lang = getLangCode( data.lang ) or i18nDefaultLanguage if propertyId == 'P1680' then -- if there is a default language for _, statement in pairs( statements ) do if statement and statement.mainsnak and statement.mainsnak.datavalue and statement.mainsnak.datavalue.value and statement.mainsnak.datavalue.value.language == lang then --found default language string appendImpl( statement.mainsnak.datavalue, statement.qualifiers, data, propertyName, options ) return end end end for _, statement in pairs( statements ) do if statement and statement.mainsnak and statement.mainsnak.datavalue then appendImpl( statement.mainsnak.datavalue, statement.qualifiers or {}, data, propertyName, options ) if propertyName == 'publication-id' and statement.qualifiers then data[ 'publication-qualifiers' ] = statement.qualifiers end end end end ---@param claims table<number, statement> ---@param qualifierPropertyId string ---@param result table ---@param resultPropertyId string ---@param options table ---@return void local function appendQualifiers( claims, qualifierPropertyId, result, resultPropertyId, options ) -- do not populate twice if not claims or result[ resultPropertyId ] then return end for _, claim in pairs( claims ) do if claim.qualifiers and claim.qualifiers[ qualifierPropertyId ] then ---@type table<number, snak> local propertyQualifiers = claim.qualifiers[ qualifierPropertyId ] for _, qualifier in pairs( propertyQualifiers ) do if qualifier and qualifier.datavalue then appendImpl( qualifier.datavalue, nil, result, resultPropertyId, options ) end end end end end ---@param entityId string ---@param propertyId string ---@param value any ---@return table<number, statement> local function findClaimsByValue( entityId, propertyId, value ) local result = {} local claims = getAllStatements( entityId, propertyId ) for _, claim in pairs( claims ) do if ( claim.mainsnak and claim.mainsnak.datavalue ) then local datavalue = claim.mainsnak.datavalue if ( datavalue.type == "string" and datavalue.value == value ) or ( datavalue.type == "wikibase-entityid" and datavalue.value[ "entity-type" ] == "item" and tostring( datavalue.value.id ) == value ) then table.insert( result, claim ) end end end return result end ---@param entityId string ---@param typeEntityId string ---@return boolean local function isInstanceOf( entityId, typeEntityId ) return findClaimsByValue( entityId, 'P31', typeEntityId )[ 1 ] ~= nil end ---@param entityId string ---@param typeEntityIds string[] ---@return string ---@todo Rewrite local function getFirstType( entityId, typeEntityIds ) for _, typeEntityId in pairs( typeEntityIds ) do if isInstanceOf( entityId, typeEntityId ) then return typeEntityId end end return nil end ---@param snaks snaks ---@param data source ---@param map map ---@return void local function populateDataFromSnaks( snaks, data, map ) for _, row in ipairs( map ) do local parameterName, propertyIds = row.name, row.ids for _, propertyId in pairs( propertyIds ) do if not data[ parameterName ] and snaks[ propertyId ] then local options = {} if propertyId == 'P888' then options = { format = function( id ) return 'http://www.jstor.org/stable/' .. id end } end for _, snak in pairs( snaks[ propertyId ] ) do if snak and snak.datavalue then appendImpl( snak.datavalue, {}, data, parameterName, options ) end end end end end end ---@param entityId string | nil ---@param data source ---@param map map ---@return void local function populateDataFromEntity( entityId, data, map ) if not data.title then if not isEmpty( entityId ) then local optionsAsLinks = { format = function( text ) return { id = entityId, label = text } end } appendEntitySnaks( entityId, 'P1476', data, 'title', optionsAsLinks ) else appendEntitySnaks( entityId, 'P1476', data, 'title', {} ) end appendEntitySnaks( entityId, 'P1680', data, 'subtitle', {} ) end local bookSeriesStatements = getBestStatements( entityId, 'P361' ) for _, statement in pairs( bookSeriesStatements ) do if statement and statement.mainsnak and statement.mainsnak.datavalue and statement.mainsnak.datavalue.value and statement.mainsnak.datavalue.value.id then local possibleBookSeriesEntityId = statement.mainsnak.datavalue.value.id if isInstanceOf( possibleBookSeriesEntityId, 'Q277759' ) then appendImpl_toTable( data, 'bookSeries' ) table.insert( data.bookSeries, { id = possibleBookSeriesEntityId } ) appendQualifiers( { statement }, 'P478', data, 'bookSeriesVolume', {} ) appendQualifiers( { statement }, 'P433', data, 'bookSeriesIssue', {} ) end end end for _, row in ipairs( map ) do local parameterName, propertyIds = row.name, row.ids for _, propertyId in pairs( propertyIds ) do local options = {} if propertyId == 'P888' then options = { format = function( id ) return 'http://www.jstor.org/stable/' .. id end } end appendEntitySnaks( entityId, propertyId, data, parameterName, options ) end end end ---@param data source ---@return void local function expandPublication( data ) if not data[ 'publication-id' ] then return end local publicationId = getSingle( data[ 'publication-id' ] ) data.publication = {} for key, value in pairs( data ) do if not string.match( key, '^publication-' ) then data.publication[ key ] = value end end data.publication.sourceId = publicationId data.publication.title = data[ 'publication-title' ] data.publication.subtitle = data[ 'publication-subtitle' ] if data[ 'publication-qualifiers' ] then populateDataFromSnaks( data[ 'publication-qualifiers' ], data.publication, PUBLICATION_PROPERTY_MAP ) end populateDataFromEntity( publicationId, data.publication, PUBLICATION_PROPERTY_MAP ) if type( data.publication.title ) == 'table' and data.publication.title[ 1 ] then data.publication.title = data.publication.title[ 1 ] end if type( data.publication.subtitle ) == 'table' and data.publication.subtitle[ 1 ] then data.publication.subtitle = data.publication.subtitle[ 1 ] end for key, value in pairs( data.publication ) do if key ~= 'sourceId' and key ~= 'title' and key ~= 'subtitle' and key ~= 'url' and not data[ key ] then data[ key ] = value end end end ---@param data source ---@return void local function expandBookSeries( data ) local bookSeries = data.bookSeries if not bookSeries then return end -- use only first one if type( bookSeries ) == 'table' and bookSeries[ 1 ] and bookSeries[ 1 ].id then data.bookSeries = bookSeries[ 1 ] bookSeries = data.bookSeries end if not bookSeries or not bookSeries.id then return end appendEntitySnaks( bookSeries.id, 'P123', data, 'publisher', {} ) appendEntitySnaks( bookSeries.id, 'P291', data, 'place', {} ) appendEntitySnaks( bookSeries.id, 'P236', data, 'issn', {} ) end ---@param entityId string ---@return string | nil local function getNormativeTitle( entityId ) local possibleTypeIds = {} for typeId, _ in pairs( NORMATIVE_DOCUMENTS ) do table.insert( possibleTypeIds, typeId ) end local foundTypeId = getFirstType( entityId, possibleTypeIds ) if foundTypeId then return NORMATIVE_DOCUMENTS[ foundTypeId ] end return nil end ---@param urls table<number, string> | string ---@param text string ---@return string local function wrapInUrl( urls, text ) local url = getSingle( urls ) if string.sub( url, 1, 1 ) == ':' then return '[[' .. url .. '|' .. text .. ']]' else return '[' .. url .. ' ' .. text .. ']' end end ---@param entityId string ---@param lang string ---@return string local function getElementLink( entityId, lang ) local sitelink = getSitelink( entityId, nil ) if sitelink then return ':' .. sitelink end if lang ~= 'mul' then -- link to entity in source language sitelink = getSitelink( entityId, lang .. 'wiki' ) if sitelink then return ':' .. lang .. ':' .. sitelink end end return ':d:' .. entityId end ---@param entityId string ---@param lang string ---@return string local function getLabel( entityId, lang ) local wbStatus, label = pcall( mw.wikibase.getLabelByLang, entityId, lang ) if not wbStatus then return '' end if label and label ~= '' then return label end wbStatus, label = pcall( mw.wikibase.getLabel, entityId ) if not wbStatus then return '' end return label or '' end ---@param lang string ---@param entityId string ---@param customTitle string ---@param options table local function renderLink( lang, entityId, customTitle, options ) if not entityId then error( 'entityId is not specified' ) end if type( entityId ) ~= 'string' then error( 'entityId is not string, but ' .. type( entityId ) ) end if type( customTitle or '' ) ~= 'string' then error( 'customTitle is not string, but ' .. type( customTitle ) ) end local title = customTitle -- ISO 4 if isEmpty( title ) then local propertyStatements = getBestStatements( entityId, 'P1160' ) for _, claim in pairs( propertyStatements ) do if ( claim and claim.mainsnak and claim.mainsnak.datavalue and claim.mainsnak.datavalue.value and claim.mainsnak.datavalue.value.language == lang ) then title = claim.mainsnak.datavalue.value.text -- mw.log( 'Got title of ' .. entityId .. ' from ISO 4 claim: «' .. title .. '»' ) break end end end -- official name P1448 -- short name P1813 if isEmpty( title ) and options.short then local propertyStatements = getBestStatements( entityId, 'P1813' ) for _, claim in pairs( propertyStatements ) do if ( claim and claim.mainsnak and claim.mainsnak.datavalue and claim.mainsnak.datavalue.value and claim.mainsnak.datavalue.value.language == lang ) then title = claim.mainsnak.datavalue.value.text -- mw.log( 'Got title of ' .. entityId .. ' from short name claim: «' .. title .. '» (' .. lang .. ')' ) break end end end -- person name P1559 -- labels if isEmpty( title ) then title = getLabel( entityId, lang ) -- mw.log( 'Got title of ' .. entityId .. ' from label: «' .. title .. '» (' .. lang .. ')' ) end local actualText = title or '\'\'(untranslated)\'\'' local link = getElementLink( entityId, lang ) return wrapInUrl( link, actualText ) end ---@param lang string ---@param value value ---@param options options ---@return string local function asString( lang, value, options ) if type( value ) == 'string' then return options.format( value ) end if type( value ) ~= 'table' then return options.format( '(unknown type)' ) end if value.id then -- this is link if type( value.label or '' ) ~= 'string' then mw.logObject( value, 'error value' ) error( 'label of table value is not string but ' .. type( value.label ) ) end local title if options.preferids then title = value.id elseif options.nolinks then title = value.label or getLabel( value.id, lang ) else title = renderLink( lang, value.id, value.label, options ) end if title == '' then title = "''(untranslated title)''" end return options.format( title ) end local resultList = {} for _, tableValue in pairs( value ) do table.insert( resultList, asString( lang, tableValue, options ) ) end return mw.text.listToText( resultList, options.separator, options.conjunction ) end ---@param entityId string ---@param data source ---@return source local function populateSourceDataImpl( entityId, data, map ) local wsLink = getSitelink( entityId, 'ruwikisource' ) if wsLink and not mw.ustring.gmatch( wsLink, 'Категория:' ) then data.url = ":ru:s:" .. wsLink end populateDataFromEntity( entityId, data, map ) local normativeTitle = getNormativeTitle( entityId ) if normativeTitle then local y, m, d = mw.ustring.match( getSingle( data.dateOfCreation ) , "(%-?%d+)%-(%d+)%-(%d+)T" ) y, m, d = tonumber( y ),tonumber( m ), tonumber( d ) local title = asString( 'ru', data.title, options_commas_nolinks ) local docNumber = getSingle( data.docNumber ) data.title = { normativeTitle .. " от&nbsp;" .. tostring( d ) .. "&nbsp;" .. monthGen[ m ] .. " " .. tostring( y ) .. "&nbsp;г." .. ( docNumber and ( " №&nbsp;" .. docNumber ) or '' ) .. ' «' .. title.. '»' } end if not data.title then local lang = getLangCode( data.lang ) or i18nDefaultLanguage local label = getLabel( entityId, lang ) if label ~= '' then data.title = { label } end end return data end ---@param entityId string ---@param propertyId string ---@param data source ---@return void local function expandSpecialsQualifiers( entityId, propertyId, data ) local statements = getBestStatements( entityId, propertyId ) for _, statement in pairs( statements ) do populateDataFromSnaks( statement.qualifiers or {}, data, PROPERTY_MAP ) end end ---Expand special types of references when additional data could be found in OTHER entity properties ---@param data source ---@return void local function expandSpecials( data ) if not data.entityId then return end if data.sourceId == 'Q36578' then -- Gemeinsame Normdatei -- specified by P227 appendEntitySnaks( data.entityId, 'P227', data, 'part', { format = function(gnd ) return 'Record #' .. gnd; end } ) appendEntitySnaks( data.entityId, 'P227', data, 'url', { format = function(gnd ) return 'http://d-nb.info/gnd/' .. gnd .. '/'; end } ) data.year = '2012—2016' expandSpecialsQualifiers( data.entityId, 'P227', data ) elseif data.sourceId == 'Q15222191' then -- BNF -- specified by P268 appendEntitySnaks( data.entityId, 'P268', data, 'part', { format = function(id ) return 'Record #' .. id; end } ) appendEntitySnaks( data.entityId, 'P268', data, 'url', { format = function(id ) return 'http://catalogue.bnf.fr/ark:/12148/cb' .. id; end } ) expandSpecialsQualifiers( data.entityId, 'P268', data ) elseif data.sourceId == 'Q54919' then -- VIAF -- specified by P214 appendEntitySnaks( data.entityId, 'P214', data, 'part', { format = function(id ) return 'Record #' .. id; end } ) appendEntitySnaks( data.entityId, 'P214', data, 'url', { format = function(id ) return 'https://viaf.org/viaf/' .. id; end } ) expandSpecialsQualifiers( data.entityId, 'P214', data ) else -- generic property search for _, sourceClaim in pairs( getBestStatements( data.sourceId, 'P1687' ) ) do if sourceClaim.mainsnak.snaktype == 'value' then local sourcePropertyId = sourceClaim.mainsnak.datavalue.value.id for _, sourcePropertyClaim in pairs( getBestStatements( sourcePropertyId, 'P1630' ) ) do if sourcePropertyClaim.mainsnak.snaktype == 'value' then appendEntitySnaks( data.entityId, sourcePropertyId, data, 'url', { format = function( id ) return mw.ustring.gsub( mw.ustring.gsub( sourcePropertyClaim.mainsnak.datavalue.value, '$1', id ), ' ', '%%20' ) end } ) expandSpecialsQualifiers( data.entityId, sourcePropertyId, data ) break end end end end end -- do we have appropriate record in P1433 ? local claims = findClaimsByValue( currentEntityId, 'P1343', data.sourceId ) if claims and #claims ~= 0 then for _, claim in pairs( claims ) do populateDataFromSnaks( claim.qualifiers, data, PROPERTY_MAP ) populateDataFromEntity( data.sourceId, data, PROPERTY_MAP ) end end end ---@param text string ---@param tip string ---@return string local function toTextWithTip( text, tip ) return '<span title="' .. tip .. '" style="border-bottom: 1px dotted; cursor: help; white-space: nowrap">' .. text .. '</span>' end ---@param lang string ---@param placeId string ---@return string local function getPlaceName( placeId, lang ) -- ГОСТ Р 7.0.12—2011 if lang == 'ru' then if placeId == 'Q649' then return toTextWithTip( 'М.', 'Москва' ); end if placeId == 'Q656' then return toTextWithTip( 'СПб.', 'Санкт-Петербург' ); end if placeId == 'Q891' then return toTextWithTip( 'Н. Новгород', 'Нижний Новгород' ); end if placeId == 'Q908' then return toTextWithTip( 'Ростов н/Д.', 'Ростов-на-Дону' ); end end return nil end ---@param data source ---@param lang string ---@return void local function preprocessPlace( data, lang ) if not data.place then return end ---@type table<number, string> local newPlace = {} for index, place in pairs( data.place ) do if place.id then local newPlaceStr = getPlaceName( place.id, lang ) if newPlaceStr then newPlace[ index ] = newPlaceStr else newPlace[ index ] = getLabel( place.id, lang ) end else newPlace[ index ] = place end end data.place = newPlace end ---@param entityId string ---@param lang string ---@param providedLabel string | nil ---@param options options ---@return string local function getPersonNameAsLabel( entityId, lang, providedLabel, options ) -- would custom label provided we don't need to check entity at all if not isEmpty( providedLabel ) then return options.format( providedLabel ) end if lang == 'mul' then lang = i18nDefaultLanguage end ---@type string | nil local personName = getLabel( entityId, lang ) if isEmpty( personName ) then return '\'\'(not translated to ' .. lang .. ')\'\'' end if not isInstanceOf( entityId, 'Q5' ) then return personName end return options.format( personName ) end ---@param entityId string ---@param lang string ---@param customLabel string | nil ---@param options options ---@return string local function getPersonNameAsWikitext( entityId, lang, customLabel, options ) local personName = getPersonNameAsLabel( entityId, lang, customLabel, options ) local link = getElementLink( entityId, lang ) return wrapInUrl( link, personName ) end ---@param value value ---@param lang string ---@param options options ---@return string local function getPeopleAsWikitext( value, lang, options ) if type( value ) == 'string' then return options.format( value ) elseif type( value ) == 'table' then if value.id then -- this is link if options.preferids then return tostring( value.id ) else if options.nolinks then return getPersonNameAsLabel( value.id, lang, value.label, options ) else return getPersonNameAsWikitext( value.id, lang, value.label, options ) end end end local maxAuthors = 10 -- need some restrictions, as some publications have enormous amount of authors (e.g. 115 authors of Q68951544) local resultList = {} for _, tableValue in pairs( value ) do local nextWikitext = getPeopleAsWikitext( tableValue, lang, options ) if not isEmpty( nextWikitext ) then table.insert( resultList, nextWikitext ) if #resultList == maxAuthors + 1 then -- keep one more to indicate that there are too many break end end end local resultWikitext = '' for i, wikitext in pairs( resultList ) do if i == maxAuthors + 1 then resultWikitext = resultWikitext .. ( i18nEtAl[ lang ] or i18nEtAlDefault ) break end if i ~= 1 then resultWikitext = resultWikitext .. ', ' end resultWikitext = resultWikitext .. wikitext end return resultWikitext end return '' -- options.format( '(unknown type)' ) end ---@param lang string ---@param data source ---@return string local function generateAuthorLinks( lang, data ) local result = '' if data.author then result = getPeopleAsWikitext( data.author, lang, options_commas_authors ) result = '<i class="wef_low_priority_links">' .. result .. '</i> ' end return result end ---@param lang string ---@param data source ---@param conjunction string ---@param propertyName string ---@param urlPropertyName string? ---@return string local function appendProperty( lang, data, conjunction, propertyName, urlPropertyName ) if not data[ propertyName ] then return '' end local out if urlPropertyName and data[ urlPropertyName ] then out = wrapInUrl( data[ urlPropertyName ], asString( lang, data[ propertyName ], options_commas_nolinks ) ) else out = asString( lang, data[ propertyName ], options_commas ) end if not out or out == '' then return '' end return conjunction .. out end ---@param lang string ---@param data source ---@return string local function appendTitle( lang, data ) local conjunction = '' local result = '' if data.part then result = result .. appendProperty( lang, data, '', 'part', 'parturl' ) conjunction = ' // ' end return result .. appendProperty( lang, data, conjunction, 'title', 'url' ) end ---@param lang string ---@return string local function appendLanguage( lang ) if lang == i18nDefaultLanguage then return '' end ---@type { getRefHtml: ( fun( lang: string ): string ), list_ref: ( fun( frame: frame ): string ) } local langs = require( 'Module:Languages' ) return langs.list_ref( p.currentFrame:newChild{ args = { lang } } ) end ---@param lang string ---@param data source ---@return string local function appendSubtitle( lang, data ) return appendProperty( lang, data, ': ', 'subtitle', nil ) end ---@param lang string ---@param data source ---@return string local function appendOriginalTitle( lang, data ) return appendProperty( lang, data, ' = ', 'originaltitle', nil ) end ---@param lang string ---@param data source ---@return string local function appendPublication( lang, data ) if not data.publication then return '' end local result = ' // ' .. asString( lang, data.publication.title, options_commas_it_short ) if data.publication.subtitle and data.publication.subtitle ~= '' then result = result .. ': ' .. asString( lang, data.publication.subtitle, options_commas_it_short ) end return result end ---@param lang string ---@param data source ---@return string local function appendEditor( lang, data ) if not data.editor and not data.translator then return '' end local result = ' / ' if data.editor then local prefix = i18nEditors[ lang ] or i18nEditors[ i18nDefaultLanguage ] result = result .. prefix .. getPeopleAsWikitext( data.editor, lang, options_commas_responsible ) if data.translator then result = result .. ', ' end end if data.translator then local prefix = i18nTranslators[ lang ] or i18nTranslators[ i18nDefaultLanguage ] result = result .. prefix .. getPeopleAsWikitext( data.translator, lang, options_commas_responsible ) end return result end ---@param lang string ---@param data source local function appendEdition( lang, data ) return appendProperty( lang, data, ' — ', 'edition', nil ) end ---@param lang string ---@param data source ---@return string local function appendPublicationData( lang, data ) if not data.place and not data.publisher and not data.year then return '' end local result = ' — ' if data.place then result = result .. asString( lang, data.place, options_commas_short ) if data.publisher or data.year then result = result .. ': ' end end if data.publisher then result = result .. asString( lang, data.publisher, options_commas_short ) if data.year then result = result .. ', ' end end if data.year then result = result .. asString( lang, data.year, options_commas ) end result = result .. '.' return result end ---@param lang string ---@param data source ---@return string local function appendVolumeAndIssue( lang, data ) if not data.volume and not data.issue then return '' end local result = ' — ' local letter_vol = i18nVolume[ lang ] or i18nVolume[ i18nDefaultLanguage ] local letter_iss = i18nIssue[ lang ] or i18nIssue[ i18nDefaultLanguage ] if data.volume then result = result .. appendProperty( lang, data, letter_vol .. '&nbsp;', 'volume', nil ) result = result ..appendProperty( lang, data, ', ' .. letter_iss .. '&nbsp;', 'issue', nil ) else result = result .. appendProperty( lang, data, letter_iss .. '&nbsp;', 'issue', nil ) end result = result .. '.' return result end ---@param lang string ---@param data source ---@return string local function appendPages( lang, data ) if not data.pages then return '' end local letter = i18nPages[ lang ] or i18nPages[ i18nDefaultLanguage ] local strPages = asString( lang, data.pages, options_commas ) strPages = mw.ustring.gsub( strPages, '[-—]', '—' ) return ' — ' .. letter .. '&nbsp;' .. strPages .. '.' end ---@param lang string ---@param data source ---@return string local function appendNumberOfPages( lang, data ) if not data.numberOfPages then return '' end local letter = i18nNumberOfPages[ lang ] or i18nNumberOfPages[ i18nDefaultLanguage ] return appendProperty( lang, data, ' — ', 'numberOfPages', nil ) .. '&nbsp;' .. letter end ---@param lang string ---@param data source ---@return string local function appendBookSeries( lang, data ) if not data.bookSeries then return '' end local result = appendProperty( lang, data, ' — (', 'bookSeries', nil ) if data.bookSeriesVolume or data.bookSeriesIssue then result = result .. '; ' local letter_vol = i18nVolume[ lang ] or i18nVolume[ i18nDefaultLanguage ] local letter_iss = i18nIssue[ lang ] or i18nIssue[ i18nDefaultLanguage ] if data.bookSeriesVolume then result = result .. appendProperty( lang, data, letter_vol .. '&nbsp;', 'bookSeriesVolume', nil ) result = result .. appendProperty( lang, data, ', ' .. letter_iss .. '&nbsp;', 'bookSeriesIssue', nil ) else result = result .. appendProperty( lang, data, letter_iss .. '&nbsp;', 'bookSeriesIssue', nil ) end end result = result .. ')' return result end ---@param lang string ---@param data source ---@return string local function appendTirage( lang, data ) if not data.tirage then return '' end local tirageTemplate = i18nTirage[ lang ] or i18nTirage[ i18nDefaultLanguage ] ---@type options local optionsTirage = { separator = '; ', conjunction = '; ', format = function( _data ) return tostring( mw.ustring.format( tirageTemplate, _data ) ) end, short = false, nolinks = false, preferids = false, } return ' — ' .. asString( lang, data.tirage, optionsTirage ) end ---@param lang string ---@param value string | nil ---@param options options ---@param prefix string? ---@return string local function appendIdentifier( lang, value, options, prefix ) if not value then return '' end return ' — ' .. ( prefix or '' ) .. asString( lang, value, options ) end ---@param result string ---@param lang string ---@param data source ---@return string local function wrapSourceId( result, lang, data ) if not data.sourceId then return result end local citeType = data.type and asString( lang, data.type, options_citetypes ) or 'citetype_unknown' return '<span class="wikidata_cite ' .. citeType .. '" data-entity-id="' .. data.sourceId .. '">' .. result .. '</span>' end ---@param data source ---@return string local function appendAccessDate( data ) if not data.accessdate then return '' end local date = getSingle( data.accessdate ) local pattern = "(%-?%d+)%-(%d+)%-(%d+)T" local y, m, d = mw.ustring.match( date, pattern ) y, m, d = tonumber( y ), tonumber( m ), tonumber( d ) local date_str = ( d > 0 and ' ' .. tostring( d ) or '' ) .. ( m > 0 and ' ' .. monthGen[ m ] or '' ) .. ( y > 0 and ' ' .. tostring( y ) or '' ) return " <small>Проверено" .. date_str .. ".</small>" end ---@param data source ---@param lang string ---@return void local function populateUrl( data, lang ) if data.sourceId and not data.url then local sitelink = getSitelink( data.sourceId, lang .. 'wikisource' ) if sitelink then data.url = ':' .. lang .. ':s:' .. sitelink end end end ---@param data source ---@return void local function populateYear( data ) if not data.year and data.dateOfPublication then local date = getSingle( data.dateOfPublication ) data.year = mw.ustring.sub( date, 2, 5 ) end if not data.year and data.dateOfCreation then local date = getSingle( data.dateOfCreation ) data.year = mw.ustring.sub( date, 2, 5 ) end end ---@param data source ---@return void local function populateTitle( data ) data.title = data.title or getSingle( data.url ) end ---@param data source ---@return string local function renderSource( data ) local lang = getLangCode( data.lang ) or i18nDefaultLanguage preprocessPlace( data, lang ) populateUrl( data, lang ) populateTitle( data ) if not data.title then return '' end populateYear( data ) local result = generateAuthorLinks( lang, data ) result = result .. appendTitle( lang, data ) result = result .. appendLanguage( lang ) result = result .. appendSubtitle( lang, data ) result = result .. appendOriginalTitle( lang, data ) result = result .. appendPublication( lang, data ) result = result .. '<span class="wef_low_priority_links">' result = result .. appendEditor( lang, data ) -- Might take current editor instead of actual. Use with caution result = result .. appendEdition( lang, data ) result = result .. appendPublicationData( lang, data ) result = result .. appendVolumeAndIssue( lang, data ) result = result .. appendPages( lang, data ) result = result .. appendNumberOfPages( lang, data ) result = result .. appendBookSeries( lang, data ) result = result .. appendTirage( lang, data ) result = result .. appendIdentifier( lang, data.isbn, options_commas, 'ISBN ' ) result = result .. appendIdentifier( lang, data.issn, options_issn, 'ISSN ' ) result = result .. appendIdentifier( lang, data.doi, options_doi, nil ) result = result .. appendIdentifier( lang, data.pmid, options_pmid, nil ) result = result .. appendIdentifier( lang, data.arxiv, options_arxiv, nil ) result = result .. appendAccessDate( data ) result = result .. '</span>' return wrapSourceId( result, lang, data ) end ---@param data source Данные в простом формате, согласованном с модулями формирования библиографического описания ---@param snaks snaks ---@return string | nil local function renderReferenceImpl( data, snaks ) -- не показывать источники с "импортировано из" if snaks.P143 then return nil end -- забрать данные из reference populateDataFromSnaks( snaks or {}, data, PROPERTY_MAP ) data.sourceId = getSingle( data.sourceId ) populateDataFromEntity( data.sourceId, data, PROPERTY_MAP ) expandSpecials( data ) populateSourceDataImpl( data.sourceId, data, PROPERTY_MAP ) expandPublication( data ) expandBookSeries( data ) if next( data ) == nil then return nil end local rendered = renderSource( data ) if mw.ustring.len( rendered ) == 0 then return nil end if data.ref then local anchorValue = 'CITEREF' .. data.ref .. ( coalesce( { data[ 'ref-year' ], data.year } ) or '' ) rendered = '<span class="citation" id="' .. mw.uri.anchorEncode( anchorValue ) .. '">' .. rendered .. '</span>' end return rendered end ---@param frame frame ---@param currentEntityId string | { id: string } ---@param reference table{ snaks: snaks } ---@return string | nil function p.renderSource( frame, currentEntityId, reference ) reference = reference or { snaks = {} } p.currentFrame = frame local data = getFilledArgs( frame.args or {} ) populateDataFromSnaks( reference.snaks, data, PROPERTY_MAP ) data.sourceId = getSingle( data.sourceId ) if not currentEntityId then data.entityId = mw.wikibase.getEntityIdForCurrentPage() elseif type( currentEntityId ) == 'string' then data.entityId = currentEntityId elseif type( currentEntityId ) == 'table' and currentEntityId.id then data.entityId = currentEntityId.id end ---@type string local rendered = renderReferenceImpl( data, reference.snaks or {} ) if not rendered then return '' end return rendered end ---@param frame frame ---@param currentEntityId string ---@param reference table ---@return string function p.renderReference( frame, currentEntityId, reference ) local rendered = p.renderSource( frame, currentEntityId, reference ) if not rendered or rendered == '' then return '' end -- Про выбор алгоритма хеширования см. [[Модуль:Hash]]. Знак подчёркивания в начале позволяет -- исключить ошибку, когда имя сноски — чисто числовое значение, каковыми иногда бывают хеши. return frame:extensionTag( 'ref', rendered, { name = '_' .. mw.hash.hashValue( 'fnv164', rendered ) } ) .. '[[Category:Википедия:Статьи с источниками из Викиданных]]' end ---@param frame frame ---@return string | nil function p.testPersonNameToAuthorName( frame ) return personNameToAuthorName( frame.args[ 1 ] ) end ---@param frame frame ---@return string | nil function p.testPersonNameToResponsibleName( frame ) return personNameToResponsibleName( frame.args[ 1 ] ) end return p 752a204827a41ecd6cf518bdb22da12718bca2ec Модуль:WikidataSelectors 828 33 64 63 2025-01-25T21:00:17Z Vallenland 2 1 версия импортирована Scribunto text/plain local i18n = { ["errors"] = { ["rank-not-valid"] = "Некорретное значение приоритета (rank)", ["cant-parse-condition"] = "Не удалось разобрать условие" } } local validRanks = { 'best', 'preferred', 'normal', 'deprecated' } --[[ Internal function for error message Input: key in errors table Output: error message ]] local function throwError( key ) error( i18n.errors[key] ) end local p = {} --[[ Load property and filter statements Input: entityId, selector string Output: filtered statements table ]] function p.load( entityId, propertySelector ) local propertyId = mw.ustring.match( propertySelector, '^[Pp]%d+' ) if not propertyId then return nil end propertyId = string.upper( propertyId ) local allStatements = {} allStatements[ propertyId ] = mw.wikibase.getAllStatements( entityId, propertyId ) return p.filter( allStatements, propertySelector ) end --[[ Parse selectors and filter statements Input: statements table, selector string Output: filtered statements table ]] function p.filter( allClaims, propertySelector ) propertySelector = mw.text.trim( propertySelector ) -- Get property ID from selector local propertyId = mw.ustring.match( propertySelector, '^[Pp]%d+' ) if not propertyId then propertyId = '' end local initPos = #propertyId + 1 propertyId = string.upper( propertyId ) if ( not allClaims ) then return nil end local allPropertyClaims = allClaims[propertyId] if ( not allPropertyClaims ) then return nil end -- Gathering rules local rules = p.matchSelectors( propertySelector, initPos ) -- If there is no rank filter, than default rank is 'best' local isRanked = false for i, subRules in ipairs( rules ) do for j, rule in ipairs( subRules ) do if rule['type'] == 'rank' then isRanked = true break end end end if not isRanked then table.insert( rules, 1, { { type = 'rank', value = 'best' } } ) end -- Execute rules allPropertyClaims = p.applyRules( allPropertyClaims, rules ) return allPropertyClaims end --[[ Match and gather selector rules Input: string with selectors rules, start position Output: rules table ]] function p.matchSelectors( selectorsString, initPos ) local rules = {} local rawRulePattern = '^%s*%[%s*[^%[%]]+%s*%]%s*' local rulePattern = '^%s*%[%s*([^%[%]]+)%s*%]%s*$' if not initPos then initPos = 1 end local rawRule = mw.ustring.match( selectorsString, rawRulePattern, initPos ) while rawRule do initPos = initPos + #rawRule rule = mw.ustring.match( rawRule, rulePattern ) rule = mw.text.trim( rule ) local subRules = mw.text.split( rule, '%s*,%s*' ) local commands = {} local comm for i, subRule in ipairs( subRules ) do local isInversed = false if mw.ustring.match( subRule, '^!' ) then isInversed = true subRule = mw.ustring.match( subRule, '^!%s*(.+)$' ) end -- p123[1] if mw.ustring.match( subRule, '^%d+$' ) then table.insert( commands, { type = 'position', value = subRule, inversed = isInversed } ) -- p123[rank:preferred] elseif mw.ustring.match( subRule, '^rank%s*:%s*(%a+)$' ) then rank = mw.ustring.match( subRule, '^rank%s*:%s*(%a+)$' ) table.insert( commands, { type = 'rank', value = rank, inversed = isInversed } ) -- p123[language:xx] elseif mw.ustring.match( subRule, '^language%s*:%s*([%a%-]+)$' ) then value = mw.ustring.match( subRule, '^language%s*:%s*([%a%-]+)$' ) table.insert( commands, { type = 'language', value = value, inversed = isInversed } ) -- p123[language!:xx] elseif mw.ustring.match( subRule, '^language%s*!:%s*([%a%-]+)$' ) then value = mw.ustring.match( subRule, '^language%s*!:%s*([%a%-]+)$' ) table.insert( commands, { type = 'language', value = value, inversed = not isInversed } ) -- p123[min] elseif mw.ustring.match( subRule, '^min$' ) then table.insert( commands, { type = 'value_min' } ) -- p123[max] elseif mw.ustring.match( subRule, '^max$' ) then table.insert( commands, { type = 'value_max' } ) -- p123[min:p456] elseif mw.ustring.match( subRule, '^min%s*:%s*[Pp]%d+$' ) then value = mw.ustring.match( subRule, ':%s*([Pp]%d+)$' ) table.insert( commands, { type = 'qualifier_min', qualifier = value } ) -- p123[max:p456] elseif mw.ustring.match( subRule, '^max%s*:%s*[Pp]%d+$' ) then value = mw.ustring.match( subRule, ':%s*([Pp]%d+)$' ) table.insert( commands, { type = 'qualifier_max', qualifier = value } ) -- p123[unit:q789] elseif mw.ustring.match( subRule, '^unit%s*:%s*[^%[%],:]+$' ) then value = mw.ustring.match( subRule, ':%s*([^%[%],:]+)$' ) table.insert( commands, { type = 'unit', value = value, inversed = isInversed } ) -- p123[unit!:q789] elseif mw.ustring.match( subRule, '^unit%s*!:%s*[^%[%],:]+$' ) then value = mw.ustring.match( subRule, '!:%s*([^%[%],:]+)$' ) table.insert( commands, { type = 'unit', value = value, inversed = not isInversed } ) -- p123[p456] elseif mw.ustring.match( subRule, '^[Pp]%d+$' ) then qualifier = mw.ustring.match( subRule, '^[Pp]%d+' ) table.insert( commands, { type = 'qualifier', qualifier = qualifier, value = nil, inversed = isInversed } ) -- p123[p456:q789] elseif mw.ustring.match( subRule, '^[Pp]%d+%s*:%s*[^%[%],:]+$' ) then qualifier = mw.ustring.match( subRule, '^([Pp]%d+)%s*:?' ) value = mw.ustring.match( subRule, ':%s*([^%[%],:]+)$' ) table.insert( commands, { type = 'qualifier', qualifier = qualifier, value = value, inversed = isInversed } ) -- p123[p456!:q789] elseif mw.ustring.match( subRule, '^[Pp]%d+%s*!:%s*[^%[%],:]+$' ) then qualifier = mw.ustring.match( subRule, '^([Pp]%d+)%s*!:?' ) value = mw.ustring.match( subRule, '!:%s*([^%[%],:]+)$' ) table.insert( commands, { type = 'qualifier', qualifier = qualifier, value = value, inversed = not isInversed } ) -- p123[q456] elseif mw.ustring.match( subRule, '^[Qq]%d+$' ) then value = mw.ustring.match( subRule, '^[Qq]%d+' ) table.insert( commands, { type = 'value', value = value, inversed = isInversed } ) else throwError( 'cant-parse-condition' ) end end if #commands then table.insert( rules, commands ) end rawRule = mw.ustring.match( selectorsString, rawRulePattern, initPos ) end return rules end --[[ Intercept statements with selector rules Input: statements table, selector rules Output: filtered statements table ]] function p.applyRules( claims, rules ) for i, subRules in ipairs( rules ) do local newClaims = {} for j, rule in ipairs( subRules ) do if rule['type'] == 'rank' then table.insert( newClaims, p.filterByRank( claims, rule['value'], rule['inversed'] ) ) elseif rule['type'] == 'language' then table.insert( newClaims, p.filterByLanguage( claims, rule['value'], rule['inversed'] ) ) elseif rule['type'] == 'unit' then table.insert( newClaims, p.filterByUnit( claims, rule['value'], rule['inversed'] ) ) elseif rule['type'] == 'position' then table.insert( newClaims, p.filterByPosition( claims, rule['value'], rule['inversed'] ) ) elseif rule['type'] == 'qualifier' then table.insert( newClaims, p.filterByQualifier( claims, rule['qualifier'], rule['value'], rule['inversed'] ) ) elseif rule['type'] == 'qualifier_min' then table.insert( newClaims, p.filterUtterByQualifier( claims, rule['qualifier'], true ) ) elseif rule['type'] == 'qualifier_max' then table.insert( newClaims, p.filterUtterByQualifier( claims, rule['qualifier'], false ) ) elseif rule['type'] == 'value' then table.insert( newClaims, p.filterByValue( claims, rule['value'], rule['inversed'] ) ) elseif rule['type'] == 'value_min' then table.insert( newClaims, p.filterUtter( claims, true ) ) elseif rule['type'] == 'value_max' then table.insert( newClaims, p.filterUtter( claims, false ) ) end end claims = {} --[[ Merge all claims TODO: It's not good ]] for j, newSubClaims in ipairs( newClaims ) do for k, newClaim in ipairs( newSubClaims ) do local isNew = true for l, oldClaim in ipairs( claims ) do if oldClaim['id'] == newClaim['id'] then isNew = false break end end if isNew then table.insert( claims, newClaim ) end end end end return claims end --[[ Filter statements by rank Input: claims table, rank value, inversion Output: filtered statements table ]] function p.filterByRank( claims, rank, inversed ) if not inversed then inversed = false end if not rank then rank = 'best' end -- Check if rank value is valid local isValidRank = false for i, validRank in ipairs( validRanks ) do if rank == validRank then isValidRank = true break end end if not isValidRank then throwError( 'rank-not-valid' ) end -- Find the best rank if rank == 'best' then rank = 'normal' -- default rank (don't use deprecated even if it's no more claims) -- If we have at least one preferred rank, mark it as best for i, statement in pairs( claims ) do if (statement.rank == 'preferred') then rank = 'preferred' break end end end local resultClaims = {}; for i, statement in pairs( claims ) do if ( statement.rank == rank ) ~= inversed then table.insert( resultClaims, statement ) end end return resultClaims end --[[ Filter statements by language of value Input: claims table, language, inversion Output: filtered statements table ]] function p.filterByLanguage( claims, language, inversed ) if not inversed then inversed = false end local resultClaims = {} local mulStatement = {} for i, statement in ipairs( claims ) do isMatchLanguage = false if statement['mainsnak'] and statement['mainsnak']['datavalue'] and statement['mainsnak']['datavalue']['value'] and statement['mainsnak']['datavalue']['value']['language'] then if statement['mainsnak']['datavalue']['value']['language'] == language then isMatchLanguage = true end if statement['mainsnak']['datavalue']['value']['language'] == 'mul' then mulStatement = statement end end if isMatchLanguage ~= inversed then table.insert( resultClaims, statement ) end end if next(resultClaims) == nil and next(mulStatement) ~= nil then -- if specific language is not found, but there is Q20923490 value table.insert( resultClaims, mulStatement ) end return resultClaims end --[[ Filter statements by unit of value Input: claims table, unit, inversion Output: filtered statements table ]] function p.filterByUnit( claims, unit, inversed ) if not inversed then inversed = false end unit = 'http://www.wikidata.org/entity/' .. string.upper( unit ) local resultClaims = {} for i, statement in ipairs( claims ) do isMatchUnit = false if statement['mainsnak'] and statement['mainsnak']['datavalue'] and statement['mainsnak']['datavalue']['value'] and statement['mainsnak']['datavalue']['value']['unit'] and statement['mainsnak']['datavalue']['value']['unit'] == unit then isMatchUnit = true end if isMatchUnit ~= inversed then table.insert( resultClaims, statement ) break end end return resultClaims end --[[ Filter statements by position Input: claims table, position, inversion Output: filtered statements table ]] function p.filterByPosition( claims, position, inversed ) if not inversed then inversed = false end local resultClaims = {}; for statementPosition, statement in ipairs( claims ) do if ( statementPosition == tonumber( position ) ) ~= inversed then table.insert( resultClaims, statement ) break end end return resultClaims end --[[ Filter statements by qualifier existance or it's value Input: claims table, ID of qualifier's property, qualifier's value, inversion Output: filtered statements table ]] function p.filterByQualifier( claims, qualifierId, value, inversed ) if not inversed then inversed = false end qualifierId = string.upper( qualifierId ) local resultClaims = {} for i, statement in ipairs( claims ) do if statement['qualifiers'] and statement['qualifiers'][qualifierId] then if value == nil then if ( #statement['qualifiers'][qualifierId] > 0 ) ~= inversed then table.insert( resultClaims, statement ) end else local isQualifierFound = false for j, qualifier in ipairs( statement['qualifiers'][qualifierId] ) do if qualifier['datavalue'] then local qualifierValue = qualifier['datavalue']['value'] if qualifier['datavalue']['type'] == 'wikibase-entityid' then qualifierValue = qualifierValue.id value = string.upper( value ) end if qualifierValue == value then isQualifierFound = true break end end end if isQualifierFound ~= inversed then table.insert( resultClaims, statement ) end end elseif inversed then table.insert( resultClaims, statement ) end end return resultClaims end --[[ Filter statements by it's values Input: claims table, value, inversed Output: filtered statements table ]] function p.filterByValue( claims, value, inversed ) inversed = inversed or false local resultClaims = {} for i, statement in ipairs( claims ) do local statementValue if statement['mainsnak'] and statement['mainsnak']['datavalue'] and statement['mainsnak']['datavalue']['type'] then statementValue = statement['mainsnak']['datavalue']['value'] if statement['mainsnak']['datavalue']['type'] == 'quantity' then statementValue = statementValue.amount end if statement['mainsnak']['datavalue']['type'] == 'time' then statementValue = statementValue.time end if statement['mainsnak']['datavalue']['type'] == 'wikibase-entityid' then statementValue = statementValue.id value = string.upper( value ) end end if ( statementValue == value ) ~= inversed then table.insert( resultClaims, statement ) end end return resultClaims end --[[ Find a statement with minimum or maximum value Input: claims table, asc, inversed Output: filtered statements table ]] function p.filterUtter( claims, asc, inversed ) local resultValue = nil for i, statement in ipairs( claims ) do local statementValue if statement['mainsnak'] and statement['mainsnak']['datavalue'] and statement['mainsnak']['datavalue']['type'] then statementValue = statement['mainsnak']['datavalue']['value'] if statement['mainsnak']['datavalue']['type'] == 'quantity' then statementValue = statementValue.amount end if statement['mainsnak']['datavalue']['type'] == 'time' then statementValue = statementValue.time end if statement['mainsnak']['datavalue']['type'] == 'wikibase-entityid' then statementValue = statementValue.id end if not resultValue or ( statementValue < resultValue ) == asc then resultValue = statementValue end end end mw.logObject( resultValue, 'resultValue' ) return p.filterByValue( claims, resultValue, inversed ) end --[[ Find a statement with minimum or maximum qualifier value Input: claims table, qualifierId, asc Output: filtered statements table ]] function p.filterUtterByQualifier( claims, qualifierId, asc ) qualifierId = string.upper( qualifierId ) local resultValue = nil local resultStatement = nil for i, statement in ipairs( claims ) do if not statement['qualifiers'] and not statement['qualifiers'][qualifierId] then if resultStatement == nil then resultStatement = statement end else for _, qualifier in ipairs( statement['qualifiers'][qualifierId] ) do if qualifier['datavalue'] then local qualifierValue = qualifier['datavalue']['value'] if qualifier['datavalue']['type'] == 'quantity' then qualifierValue = qualifierValue.amount end if qualifier['datavalue']['type'] == 'time' then qualifierValue = qualifierValue.time end if qualifier['datavalue']['type'] == 'wikibase-entityid' then qualifierValue = qualifierValue.id end if not resultValue or ( qualifierValue < resultValue ) == asc then resultStatement = statement resultValue = qualifierValue end end end end end return { resultStatement } end return p 0bdff3a63bf171160cdec5c966211fbbf3003880 Модуль:Infobox 828 35 68 67 2025-01-25T21:00:18Z Vallenland 2 1 версия импортирована Scribunto text/plain local p = {}; local yesno = require('Module:Yesno') local function _renderLine( frame, args, i ) if args[ 'заголовок' .. i ] and args[ 'заголовок' .. i ] == '-' then return '' elseif args[ 'заголовок' .. i ] and args[ 'заголовок' .. i ] ~= '' then local style = ( args[ 'стиль_заголовков' ] or '' ) .. ( args[ 'стиль_заголовка' .. i ] or '' ); local class = ( args[ 'класс' .. i ] or '' ); return '\n<tr>\n<th colspan="2" scope="colgroup" class="infobox-header ' .. class .. '" style="' .. style .. '">' .. args[ 'заголовок' .. i ] .. '</th>\n</tr>'; end if args[ 'блок' .. i ] and args[ 'блок' .. i ] ~= '' then return args[ 'блок' .. i ]; end local text = args[ 'текст' .. i ] or ''; if args[ 'викиданные' .. i ] and args[ 'викиданные' .. i ] ~= '' then text = frame:expandTemplate{ title = 'Wikidata', args = { args[ 'викиданные' .. i ], text, from = args[ 'from' ] or '' } }; end if text ~= '' then local label = args[ 'метка' .. i ] or ''; local class = args[ 'класс' .. i ] or ''; if string.find(class, 'noplainlist') == nil and string.find(class, 'nofirstlevel') == nil then class = class .. ' plainlist'; end if class ~= '' then class = ' class="' .. class .. '"'; end local style = ( args[ 'стиль_текстов' ] or '' ) .. ( args[ 'стиль_текста' ] or '' ) .. ( args[ 'стиль_текста' .. i ] or '' ); if label == '' then style = 'text-align:center;' .. style; end if style ~= '' then style = ' style="' .. style .. '"'; end if label ~= '' then local labelClass = args[ 'класс_меток' ] or ''; if string.find(labelClass, 'noplainlist') == nil and string.find(labelClass, 'nofirstlevel') == nil then labelClass = labelClass .. ' plainlist'; end if labelClass ~= '' then labelClass = ' class="' .. labelClass .. '"'; end local labelStyle = ( args[ 'стиль_меток' ] or '' ) .. ( args[ 'стиль_метки' .. i ] or '' ); if labelStyle ~= '' then labelStyle = ' style="' .. labelStyle .. '"'; end return '\n<tr>\n<th scope="row"' .. labelClass .. labelStyle .. '>' .. label .. '</th>' .. '\n<td' .. class .. style .. '>\n' .. text .. '</td>\n</tr>'; end return '\n<tr>\n<td colspan="2"' .. class .. style .. '>\n' .. text .. '</td>\n</tr>'; end return ''; end local function maxNumber ( args ) local maxNumber = 0 for argName, _ in pairs(args) do local argNumber = mw.ustring.match(argName, '^[^0-9]+([0-9]+)$') if argNumber and tonumber(argNumber) > maxNumber then maxNumber = tonumber(argNumber) end end return maxNumber end function p.renderLine( frame ) local args = frame:getParent().args; return _renderLine(frame, args, '') end function p.renderLines( frame ) local args = frame:getParent().args; local res = '' local header, text = '', '' local autoHeaders = yesno(args [ 'автозаголовки' ] or 'false', false) for i = 1, maxNumber(args) do if args[ 'заголовок' .. i ] and args[ 'заголовок' .. i ] ~= '' then if text ~= '' or not autoHeaders then res = res .. header .. text end header, text = _renderLine(frame, args, i), '' else text = text .. _renderLine(frame, args, i) end end if text ~= '' or not autoHeaders then res = res .. header .. text end return res end return p; c830c997bd3d15923f347277e3b0ae71b7ba917e Модуль:Transclude 828 36 70 69 2025-01-25T21:00:19Z Vallenland 2 1 версия импортирована Scribunto text/plain local p={} -- Вызывает внутренний шаблон с аргументами объемлющего шаблона function p.call(frame) local template = frame.args[1] local args = frame:getParent().args return frame:expandTemplate{ title=template, args=args } end -- Общая реализация для forall и call local function forallImpl(args, separator, conjunction, func) -- нумерованные ключи из args local keys = {} -- перебор в произвольном порядке, даже для нумерованных ключей for key, value in pairs(args) do if type(key) == 'number' and value and value ~= '' then table.insert(keys, key) end end table.sort(keys) local results = {} for _, key in ipairs(keys) do local value = func(args[key]) table.insert(results, value) end return mw.text.listToText(results, separator, conjunction) end -- Вызывает внутренний шаблон, передавая ему нумерованные параметры объемлющего шаблона по-одному function p.forall(frame) local template = frame.args[1] local separator = frame.args.separator or '' local conjunction = frame.args.conjunction or separator local args = frame:getParent().args local func = function(value) return frame:expandTemplate{ title = template, args = {value} } -- или другой frame? end return forallImpl(args, separator, conjunction, func) end -- Берёт нумерованные аргументы объемлющего шаблона и склеивает их в единую строку function p.join(frame) local separator = frame.args[1] or '' local conjunction = frame.args[2] or separator local args = frame:getParent().args local func = function(value) return value end return forallImpl(args, separator, conjunction, func) end -- Служебная функция: удаляет дубликаты из отсортированного массива с нумерованными индексами local function deleteDuplicates(args) local res = {} for key, value in pairs(args) do if args[key+1] ~= value then table.insert(res, value) end end return res end -- Вызывает внутренний шаблон несколько раз, передавая в него блоки аргументов объемлющего шаблона function p.npc(frame) local args = frame:getParent().args local templateFrame = frame:getParent() local template = frame.args[1] -- определение, блоки аргументов с какими номерами нужны: -- если в объемлющем шаблоне есть "параметр12" и в вызове модуля есть "параметр", то вызывается 12-й блок local nums = {} for key, _ in pairs(args) do local main, num = string.match(key, '^(.-)%s*(%d*)$') num = tonumber(num) -- учитывать "параметр12", только если задано "параметр" if num and frame.args[main] then table.insert(nums, num) end end table.sort(nums) nums = deleteDuplicates(nums) -- проходить по нужным номерам блоков по возрастанию и однократно -- подставлять в шаблон: -- 1. общие аргументы данного модуля -- 2. аргументы объемлющего шаблона вида "параметр12" как "параметр" в 12-й блок local results = {} for _, blockNum in ipairs(nums) do -- общие аргументы модуля, которые передаются в каждый блок local blockArgs = mw.clone(frame.args) -- metatable ломает expandTemplate setmetatable(blockArgs, nil) for key, value in pairs(args) do local main, num = string.match(key, '^(.-)%s*(%d*)$') num = tonumber(num) -- передавать "параметр12" как "параметр" в 12-й блок, только если есть "параметр" в вызове модуля if blockNum == num and frame.args[main] then blockArgs[main] = value end end local blockText = templateFrame:expandTemplate{ title=template; args=blockArgs } table.insert(results, blockText) end return table.concat(results) end -- Действует аналогично forall по числовой переменной, изменяющейся (по умолчанию, от 1) до f.args[2]. function p.cycle(f) local tf,ac,op=f:getParent(), {}, f.args.output or 'inline'; local sep=''; if op == 'newline' then sep='\n'; end for p,k in pairs(f.args) do if type(p)=='number' then if p>2 then ac[p-1]=k end else ac[p]=k end end local s,fh = f.args[2]:match('^%s*(%-?%d+)%s*%.%.') or 1, f.args[2]:match('%.%.%s*(%S.*)%s*$') or f.args[2] or ''; fh=tonumber(fh) or fh:match('^%s*(.-)%s*$'); s=tonumber(s); local acr={}; if not s then error('Начало цикла «'..s..'» — не число') end local function dc(order) local r=tf:expandTemplate{ title=f.args[1]; args={s,unpack(ac)} } if order == 'desc' then s=s-1; else s=s+1; end if r~='' then table.insert(acr,r); return r end end if type(fh)=='number' then if fh > s then while s<=fh do dc('asc') end else while s>=fh do dc('desc') end end elseif fh~='' then while tf:expandTemplate{ title=fh; args={s,unpack(ac)} } do dc('asc') end else while dc('asc') do end end return table.concat(acr, sep) end return p c17cfab4cebc23157f5ab8d18c7e4f5c273bfa59 Шаблон:Replace 10 37 72 71 2025-01-25T21:00:19Z Vallenland 2 1 версия импортирована wikitext text/x-wiki {{safesubst:<noinclude />#invoke:String|replace|source={{{1}}}|{{{2}}}|{{{3}}}|plain={{{plain|true}}}|count={{{count|}}}}}<noinclude> {{doc}} </noinclude> 7752c3c70ae8c46a89a0808aa282956866dbba5b Шаблон:Delink 10 38 74 73 2025-01-25T21:00:19Z Vallenland 2 1 версия импортирована wikitext text/x-wiki {{<includeonly>safesubst:</includeonly>#invoke:delink|delink}}<noinclude> {{doc}} </noinclude> dbac86e53b946e60d5b6236381e8c31858e79ee5 Модуль:Delink 828 39 76 75 2025-01-25T21:00:20Z Vallenland 2 1 версия импортирована Scribunto text/plain -- This module de-links most wikitext. require("strict") local yesno = require("Module:Yesno") local p = {} local getArgs local function delinkReversePipeTrick(s) if s:match("^%[%[|.*[|\n]") then -- Check for newlines or multiple pipes. return s end return s:match("%[%[|(.*)%]%]") end local function delinkPipeTrick(s) -- We need to deal with colons, brackets, and commas, per [[Help:Pipe trick]]. -- First, remove the text before the first colon, if any. if s:match(":") then s = s:match("%[%[.-:(.*)|%]%]") -- If there are no colons, grab all of the text apart from the square brackets and the pipe. else s = s:match("%[%[(.*)|%]%]") end -- Next up, brackets and commas. if s:match("%(.-%)$") then -- Brackets trump commas. s = s:match("(.-) ?%(.-%)$") elseif s:match(",") then -- If there are no brackets, display only the text before the first comma. s = s:match("(.-),.*$") end return s end -- Return wikilink target |wikilinks=target local function getDelinkedTarget(s) local result = s -- Deal with the reverse pipe trick. if result:match("%[%[|") then return delinkReversePipeTrick(result) end result = mw.uri.decode(result, "PATH") -- decode percent-encoded entities. Leave underscores and plus signs. result = mw.text.decode(result, true) -- decode HTML entities. -- Check for bad titles. To do this we need to find the -- title area of the link, i.e. the part before any pipes. local target_area if result:match("|") then -- Find if we're dealing with a piped link. target_area = result:match("^%[%[(.-)|.*%]%]") else target_area = result:match("^%[%[(.-)%]%]") end -- Check for bad characters. if mw.ustring.match(target_area, "[%[%]<>{}%%%c\n]") and mw.ustring.match(target_area, "[%[%]<>{}%%%c\n]") ~= "?" then return s end return target_area end local function getDelinkedLabel(s) local result = s -- Deal with the reverse pipe trick. if result:match("%[%[|") then return delinkReversePipeTrick(result) end result = mw.uri.decode(result, "PATH") -- decode percent-encoded entities. Leave underscores and plus signs. result = mw.text.decode(result, true) -- decode HTML entities. -- Check for bad titles. To do this we need to find the -- title area of the link, i.e. the part before any pipes. local target_area if result:match("|") then -- Find if we're dealing with a piped link. target_area = result:match("^%[%[(.-)|.*%]%]") else target_area = result:match("^%[%[(.-)%]%]") end -- Check for bad characters. if mw.ustring.match(target_area, "[%[%]<>{}%%%c\n]") and mw.ustring.match(target_area, "[%[%]<>{}%%%c\n]") ~= "?" then return s end -- Check for categories, interwikis, and files. local colon_prefix = result:match("%[%[(.-):.*%]%]") or "" -- Get the text before the first colon. local ns = mw.site.namespaces[colon_prefix] -- see if this is a known namespace if mw.language.isKnownLanguageTag(colon_prefix) or (ns and (ns.canonicalName == "File" or ns.canonicalName == "Category")) then return "" end -- Remove the colon if the link is using the [[Help:Colon trick]]. if result:match("%[%[:") then result = "[[" .. result:match("%[%[:(.*%]%])") end -- Deal with links using the [[Help:Pipe trick]]. if mw.ustring.match(result, "^%[%[[^|]*|%]%]") then return delinkPipeTrick(result) end -- Find the display area of the wikilink if result:match("|") then -- Find if we're dealing with a piped link. result = result:match("^%[%[.-|(.+)%]%]") -- Remove new lines from the display of multiline piped links, -- where the pipe is before the first new line. result = result:gsub("\n", "") else result = result:match("^%[%[(.-)%]%]") end return result end local function delinkURL(s) -- Assume we have already delinked internal wikilinks, and that -- we have been passed some text between two square brackets [foo]. -- If the text contains a line break it is not formatted as a URL, regardless of other content. if s:match("\n") then return s end -- Check if the text has a valid URL prefix and at least one valid URL character. local valid_url_prefixes = {"//", "http://", "https://", "ftp://", "gopher://", "mailto:", "news:", "irc://"} local url_prefix for _ ,v in ipairs(valid_url_prefixes) do if mw.ustring.match(s, '^%[' .. v ..'[^"%s].*%]' ) then url_prefix = v break end end -- Get display text if not url_prefix then return s end s = s:match("^%[" .. url_prefix .. "(.*)%]") -- Grab all of the text after the URL prefix and before the final square bracket. s = s:match('^.-(["<> ].*)') or "" -- Grab all of the text after the first URL separator character ("<> ). s = mw.ustring.match(s, "^%s*(%S.*)$") or "" -- If the separating character was a space, trim it off. local s_decoded = mw.text.decode(s, true) if mw.ustring.match(s_decoded, "%c") then return s end return s_decoded end local function delinkLinkClass(text, pattern, delinkFunction) if type(text) ~= "string" then error("Attempt to de-link non-string input.", 2) end if type(pattern) ~= "string" or mw.ustring.sub(pattern, 1, 1) ~= "^" then error('Invalid pattern detected. Patterns must begin with "^".', 2) end -- Iterate over the text string, and replace any matched text. using the -- delink function. We need to iterate character by character rather -- than just use gsub, otherwise nested links aren't detected properly. local result = "" while text ~= "" do -- Replace text using one iteration of gsub. text = mw.ustring.gsub(text, pattern, delinkFunction, 1) -- Append the left-most character to the result string. result = result .. mw.ustring.sub(text, 1, 1) text = mw.ustring.sub(text, 2, -1) end return result end function p._delink(args) local text = args[1] or "" if yesno(args.markers) == true then text = mw.text.killMarkers(text) -- [[Help:Strip markers]] end if yesno(args.refs) == true then -- Remove any [[Help:Strip markers]] representing ref tags. In most situations -- this is not a good idea - only use it if you know what you are doing! text = mw.ustring.gsub(text, "UNIQ%w*%-ref%-%d*%-QINU", "") end if not (yesno(args.comments) == false) then text = text:gsub("<!%-%-.-%-%->", "") -- Remove html comments. end if not (yesno(args.wikilinks) == false) and args.wikilinks ~= "target" then -- De-link wikilinks and return the label portion of the wikilink. text = delinkLinkClass(text, "^%[%[.-%]%]", getDelinkedLabel) elseif args.wikilinks == "target" then -- De-link wikilinks and return the target portions of the wikilink. text = delinkLinkClass(text, "^%[%[.-%]%]", getDelinkedTarget) end if not (yesno(args.urls) == false) then text = delinkLinkClass(text, "^%[.-%]", delinkURL) -- De-link URLs. end if not (yesno(args.whitespace) == false) then -- Replace single new lines with a single space, but leave double new lines -- and new lines only containing spaces or tabs before a second new line. text = mw.ustring.gsub(text, "([^\n \t][ \t]*)\n([ \t]*[^\n \t])", "%1 %2") text = text:gsub("[ \t]+", " ") -- Remove extra tabs and spaces. end return text end function p.delink(frame) if not getArgs then getArgs = require('Module:Arguments').getArgs end return p._delink(getArgs(frame, {wrappers = 'Template:Delink'})) end return p eb6cae0d369f288b0b1600633d9bf7874cefdcbc Модуль:URL 828 40 78 77 2025-01-25T21:00:20Z Vallenland 2 1 версия импортирована Scribunto text/plain function startsWith( source, substring ) if mw.ustring.len( substring ) > mw.ustring.len( source ) then return false end return mw.ustring.sub( source, 1, mw.ustring.len( substring ) ) == substring end p = {} function formatUrlImpl( source, title, length ) local scheme, host, path local postfix = '' local arg1, arg2 = source, title local isTestPage = mw.title.getCurrentTitle().prefixedText == 'Модуль:URL' -- Две квадратные скобки подряд — [[вики-ссылка]] вместо [ссылки] — возвращаем вход как есть. if string.find( arg1, "[[", 1, true ) then local result = arg1 if not isTestPage then result = result .. '[[Категория:Википедия:Статьи с вики-ссылкой, переданной в Модуль:URL]]' if arg2 then -- Если есть arg2, а мы распарсить ссылку не смогли, и значит заменить title не сможем корректно, это есть ошибка. result = result .. '[[Категория:Википедия:Статьи с ошибочной работой Модуль:URL]]' end end return result end -- Более одной квадратной скобки — скорее всего, задано более одного URL — тоже возвращаем как есть. if select(2, string.gsub( arg1, "%[", "" )) > 1 then local result = arg1 if not isTestPage then result = result .. '[[Категория:Википедия:Статьи со сложным входом в Модуль:URL]]' if arg2 then -- Если есть arg2, а мы распарсить ссылку не смогли, и значит заменить title не сможем корректно, это есть ошибка. result = result .. '[[Категория:Википедия:Статьи с ошибочной работой Модуль:URL]]' end end return result end source = mw.text.trim( source, "%[%] " ) local titleDelimeterPosition = mw.ustring.find( source, " ", 1 ) if titleDelimeterPosition then if not title or title == "" then title = mw.ustring.sub( source, titleDelimeterPosition + 1 ) local postfixDelimeterPosition = mw.ustring.find( title, "%]", 1 ) if postfixDelimeterPosition then postfix = mw.ustring.sub( title, postfixDelimeterPosition + 1 ) title = mw.ustring.sub( title, 1, postfixDelimeterPosition - 1 ) end end source = mw.ustring.sub( source, 1, titleDelimeterPosition - 1 ) end local hostStartPosition local schemeDelimeterPosition = mw.ustring.find( source, "://", 1, true ) if schemeDelimeterPosition then scheme = mw.ustring.sub( source, 1, schemeDelimeterPosition + 2) hostStartPosition = schemeDelimeterPosition + 3 elseif mw.ustring.find( source, "^//", 1 ) then scheme = "//" hostStartPosition = 3 elseif mw.ustring.find( source, "^mailto:", 1 ) then scheme = "mailto:" hostStartPosition = 8 elseif mw.ustring.find( source, "@", 1 ) then scheme = "mailto:" source = scheme .. source hostStartPosition = 8 else scheme = "http://" source = scheme .. source hostStartPosition = 8 end if title then local finds = mw.ustring.find( arg1, "[", 1, true ) if titleDelimeterPosition and finds and finds > titleDelimeterPosition + 1 then -- Если titleDelimeterPosition промазал мимо скобки и нашел пробел раньше неё, к примеру "a [b c]", -- то свернуть всю нашу хиромантию и выдать первый аргумент без изменений. if arg2 == nil then return arg1 .. (isTestPage and '' or '[[Категория:Википедия:Статьи со сложным входом в Модуль:URL]]') -- Если есть arg2, а мы распарсить ссылку не смогли, и значит заменить title не сможем корректно, это есть ошибка. -- С другой стороны, если arg2 нет, а arg1 очень сложный, то возможно это нормальный ход вещей, -- и на вход в модуль дана уже очень сильно оформленная ссылка. else return arg1 .. (isTestPage and '' or '[[Категория:Википедия:Статьи с ошибочной работой Модуль:URL]]') end end return '[' .. source .. ' ' .. title .. ']' .. postfix end local hostDelimeterPosition = mw.ustring.find( source, "/", hostStartPosition, true ) if hostDelimeterPosition then host = mw.ustring.sub( source, hostStartPosition, hostDelimeterPosition - 1 ) if hostDelimeterPosition == mw.ustring.len( source ) then path = nil else path = mw.ustring.sub( source, hostDelimeterPosition + 1 ) end else host = mw.ustring.sub( source, hostStartPosition ) end -- post-split format options if startsWith( host, 'www.' ) then host = mw.ustring.sub( host, 5 ) end host = mw.language.new( 'en' ):lc( host ) if path and path ~= '' and path ~= '/' then local title = host .. '/' .. path if length and #title > length then title = host .. '/' .. mw.ustring.sub( path, 1, length - #title - 2 ) .. '…' end return '[' .. source .. ' ' .. title .. ']' .. postfix else return '[' .. source .. ' ' .. host .. ']' .. postfix end end function p.formatUrl( frame ) local url = frame.args[1] or '' local title = frame.args[2] or '' local length = frame.args['length'] and tonumber( frame.args['length'] ) url = mw.text.trim( url ) title = mw.text.trim( title ) if url == '' then return nil end if title == '' then title = nil end return formatUrlImpl( url, title, length ) end function p.formatUrlSingle( context, options, url ) url = mw.text.trim( url ) if url == '' then return nil end local title = nil if ( options['text'] and options['text'] ~= '' ) then title = options['text'] end local length = options['length'] and tonumber( options['length'] ) return formatUrlImpl( url, title, length ) end return p a991f879e135a472238c7f589e8d20d92a856d4d Шаблон:Флагификация 10 41 80 79 2025-01-25T21:00:21Z Vallenland 2 1 версия импортирована wikitext text/x-wiki {{#if: {{{1|}}} | {{#switch: {{str left|{{{1|}}}|1}} | [ | < | { = [[Категория:Википедия:Страницы с неверным параметром шаблона Флагификация]] | #default = {{Флагификация/{{{1|}}} | Флагификация/флагификация | variant = {{{variant|{{{2|}}}}}} | размер = {{{размер|}}} }} }} }}<noinclude>{{doc}}</noinclude> 46f4b3bb9842eaf2c75057227b1b76b565563be5 Шаблон:Str left 10 42 82 81 2025-01-25T21:00:21Z Vallenland 2 1 версия импортирована wikitext text/x-wiki {{<includeonly>safesubst:</includeonly>padleft:|{{{2|1}}}|{{{1|}}}}}<noinclude> {{doc}} </noinclude> c1f57b63826f4d455dcaec8d2c24a2b8268f42ec Шаблон:Флагификация/флагификация 10 43 84 83 2025-01-25T21:00:21Z Vallenland 2 1 версия импортирована wikitext text/x-wiki <span class="nowrap" data-sort-value="{{{shortname alias|{{{alias}}}}}}"><span class="flagicon">[[File:{{{flag alias-{{{variant}}}|{{{flag alias}}}}}}|class=noresize|link=|alt=|{{#if: {{{размер|}}} | {{{размер}}} | 22x20px }}|{{{border-{{{variant}}}|{{{border|border}}}}}}]]</span>&nbsp;[[{{{alias}}}|<span class="wrap">{{{shortname alias-{{{variant}}}|{{{shortname alias|{{{alias}}}}}}}}}</span>]]</span><noinclude>{{doc}}</noinclude> 8403cde4528b4d7df313d2e82aeb40b0bb66c2c2 Шаблон:Карточка/имя 10 44 86 85 2025-01-25T21:00:21Z Vallenland 2 1 версия импортирована wikitext text/x-wiki {{#if:{{{1|}}}|{{{1}}}|{{сначала имя|{{PAGENAME}}}}}}<noinclude> {{doc}} </noinclude> c2c97d1196f5c50a2ec1aa866cd4004526a32383 Шаблон:Карточка/оригинал имени 10 45 88 87 2025-01-25T21:00:22Z Vallenland 2 1 версия импортирована wikitext text/x-wiki {{wikidata|p1559[language!:ru]|{{{1|}}}|before={{{before|}}}|separator=<br>|conjunction=<br>|monolingualLangTemplate={{{monolingualLangTemplate|lang}}}|from={{{from|}}}}}<!-- -->{{#if:{{NAMESPACE}}||{{#if:{{{1|}}}|{{#ifeq:{{#invoke:String|find|{{{1|}}}|span}}|0|[[Категория:Википедия:Статьи с оригиналом имени без шаблона lang-XX]]}}}}}}<noinclude>{{doc}}</noinclude> a294e3f7f61c5206ca5671b72e21804d7a32fcbc Шаблон:Wikidata/p569 10 46 90 89 2025-01-25T21:00:22Z Vallenland 2 1 версия импортирована wikitext text/x-wiki {{#switch:{{{1|}}}|-=|={{#invoke:Wikidata|formatStatements|property=p569|claim-module=Wikidata/date|claim-function=formatDateOfBirthClaim|nocat={{{nocat|}}}{{NAMESPACE}}|suppressAge={{{suppress age|}}}}}|{{#invoke:Infocards|dateOfBirth|{{{1|}}}|{{{2|}}}|suppressAge={{wikidata|P570|plain=true}}{{{suppress age|}}}|nocat={{{nocat|}}}{{NAMESPACE}}}}}}<noinclude>{{doc}}</noinclude> 9643ab18fcd322831b72e38658b58c6b94a914e2 Шаблон:Wikidata/p570 10 47 92 91 2025-01-25T21:00:22Z Vallenland 2 1 версия импортирована wikitext text/x-wiki {{#switch:{{{1|}}}|-=|={{#invoke:Wikidata|formatStatements|property=p570|claim-module=Wikidata/date|claim-function=formatDateOfDeathClaim|nocat={{{nocat|}}}{{NAMESPACE}}}}|{{#invoke:Infocards|dateOfDeath|{{{2|}}}|{{{1|}}}|nocat={{{nocat|}}}{{NAMESPACE}}}}}}<noinclude>{{doc}}</noinclude> a51af6d007d156cfeacb13a0a4a7471da7d4ed22 Шаблон:Nobr 10 48 94 93 2025-01-25T21:00:23Z Vallenland 2 1 версия импортирована wikitext text/x-wiki <includeonly><span class="nowrap">{{{1}}}</span></includeonly><noinclude> {{doc}} <!-- Пожалуйста, добавляйте категории и интервики на страницу документации! --> </noinclude> 989c6f164ed3a8543e916c8f1746ba1ab94fb068 Шаблон:Wikidata gender switch 10 49 96 95 2025-01-25T21:00:23Z Vallenland 2 1 версия импортирована wikitext text/x-wiki {{#switch: {{wikidata|p21|{{lc:{{delink|{{{1|}}}}}}}|plain=true|from={{{from|}}}}} | 1 | f | fem | female | feminine | ж | жен | женский | женский пол | транс-женщина | Q6581072 | Q1052281 | Q43445 = {{{2}}} | m | male | masculine | м | муж | мужской | мужской пол | транс-мужчина | Q6581097 | Q2449503 | Q44148 = {{{3}}} | #default = {{#if:{{{4|}}}|{{{4}}}|{{{3}}}}} }}<noinclude> {{doc}} </noinclude> 24ccdd5a8702a7028386e9b887d3acf1b5f81c34 Шаблон:Карточка/Викитека 10 50 98 97 2025-01-25T21:00:23Z Vallenland 2 1 версия импортирована wikitext text/x-wiki {{#ifeq:{{{1|}}}|нельзя<!-- -->|© Произведения этого автора [[Свободный контент|несвободны]]<!-- -->|{{#if:{{#invoke:Wikidata/Interproject|getWikisourceLink|p103}}<!-- -->|[[Файл:wikisource-logo.svg|15px|Логотип Викитеки|link={{#invoke:Wikidata/Interproject|getWikisourceLink|p103}}]] [[{{#invoke:Wikidata/Interproject|getWikisourceLink|p103}}|{{#if:{{{2|}}}|{{удалить теги|{{delink|{{{2}}}}}}}|{{Сначала имя|{{PAGENAME}}}}}} в Викитеке]]<!-- -->|{{#if:{{{1|}}}|[[Файл:wikisource-logo.svg|15px|Логотип Викитеки|link=[[:s:{{{1|}}}]]]] [[:s:{{{1|}}}|{{#if:{{{2|}}}|{{удалить теги|{{delink|{{{2}}}}}}}|{{Сначала имя|{{PAGENAME}}}}}} в Викитеке]]}}<!-- -->}}<!-- -->{{#if:{{{nocat|}}}{{NAMESPACE}}||{{#if:{{{1|}}}|[[Категория:Википедия:Ссылка на Викитеку непосредственно в статье]]}}}}<!-- -->}}<noinclude> {{doc}} </noinclude> aac8463be78041fae4a55bf222430b207987f063 Шаблон:Сначала имя 10 51 100 99 2025-01-25T21:00:24Z Vallenland 2 1 версия импортирована wikitext text/x-wiki {{safesubst:<noinclude />#ifexpr: {{safesubst:<noinclude />str find|{{safesubst:<noinclude />До символа|{{{1}}}|(}}|,}} = -1 <!-- -->|{{safesubst:<noinclude />До символа|{{{1}}}|(}}<!-- -->|{{safesubst:<noinclude />trim|{{safesubst:<noinclude />После символа|{{safesubst:<noinclude />До символа|{{{1}}}|(}}|,}}}} {{safesubst:<noinclude />До символа|{{safesubst:<noinclude />До символа|{{{1}}}|(}}|,}}<!-- -->}}<noinclude> {{doc}} </noinclude> c3a2e3e13dba0ae595a7c147ca692be2eb183f38 Шаблон:Str find 10 52 102 101 2025-01-25T21:00:24Z Vallenland 2 1 версия импортирована wikitext text/x-wiki {{ {{{|safesubst:}}}#invoke:String|str_find|source={{{1|}}}|{{{2|}}}}}<noinclude> {{doc}} <!-- Add categories and interwikis to the /doc subpage, not here! --> </noinclude> 18d1469d30d27a82ee15fd2fb1ca12a34b5f5e87 Шаблон:До символа 10 53 104 103 2025-01-25T21:00:24Z Vallenland 2 1 версия импортирована wikitext text/x-wiki {{ {{{|safesubst:}}}#invoke:string2|bs|{{{1|}}}|{{{2|}}}|{{{from|1}}}}}<noinclude>{{doc}}</noinclude> 4cd51dc75d5f365cffac57c9577bd2b2f5c7cc3f Модуль:Wikidata/media 828 54 106 105 2025-01-25T21:00:24Z Vallenland 2 1 версия импортирована Scribunto text/plain local p = {} -- Константы local contentLanguageCode = mw.getContentLanguage():getCode(); function p.formatCommonsCategory( context, options, value ) local link = 'commons:Category:' .. value local title = value .. ' на Викискладе' if ( options['text'] and options['text'] ~= '' ) then title = options['text'] end commons = '[[' .. link .. '|' .. title .. ']]' --Commons icon if ( not options['icon'] or options['icon'] ~= '-' ) then local icon_size = '15px' if ( options['icon_size'] and options['icon_size'] ~= '' ) then icon_size = options['icon_size'] end commons = '[[File:Commons-logo.svg|' .. icon_size .. '|link=' .. link .. '|alt=Логотип Викисклада]] ' .. commons end --Text before and after link if ( options['text_before'] and options['text_before'] ~= '' ) then if ( options['text_before'] ~= '-' ) then commons = options['text_before'] .. ' ' .. commons end end if ( options['text_after'] and options['text_after'] ~= '' ) then if ( options['text_after'] ~= '-' ) then commons = commons .. ' ' .. options['text_after'] end end return commons end --[[ Временный хак, нужно добавить config, getConfig и getCategoryByCode в options, чтобы они были доступны в любом месте кода. ]] local config; local function getCategoryByCode( code, sortkey ) if config == nil then config = require( 'Module:Wikidata/config' ); end; local value = config[ 'categories' ][ code ]; if not value or value == '' then return ''; end return '[[Category:' .. value .. ']]'; end local function getCaption( context, options ) local caption = '' if options.qualifiers and options.qualifiers.P2096 then for i, qualifier in pairs( options.qualifiers.P2096 ) do if ( qualifier and qualifier.datavalue and qualifier.datavalue.type == 'monolingualtext' and qualifier.datavalue.value and qualifier.datavalue.value.language == contentLanguageCode ) then caption = qualifier.datavalue.value.text break end end end if options['appendTimestamp'] and options.qualifiers and options.qualifiers.P585 and options.qualifiers.P585[1] then local moment = context.formatValueDefault( context, options, options.qualifiers.P585[1].datavalue ) if not caption or caption == '' then caption = moment else caption = caption .. ', ' .. moment end end local localValue = ''; if options[ 'value' ] and options[ 'value' ] ~= '' then localValue = options[ 'value' ]; end local localCaption = ''; if options[ 'caption' ] and options[ 'caption' ] ~= '' then localCaption = options[ 'caption' ]; end if localValue ~= '' then caption = localCaption; end local formattedCaption = '' if caption ~= '' then formattedCaption = context.wrapQualifier( caption, 'P2096', { class = 'media-caption', style = 'display:block' } ); end if localValue == '' and localCaption ~= '' then formattedCaption = formattedCaption .. getCategoryByCode( 'media-contains-local-caption' ) if options.frame:preprocess('{{REVISIONID}}') == '' then formattedCaption = formattedCaption .. '<span class="error" style="font-size:94%;">Локальная подпись не используется, потому что изображение берётся из Викиданных, см. [[Википедия:Шаблоны-карточки#Описание изображения в Викиданных|здесь]]</span>' end end return caption, formattedCaption end function p.formatCommonsMediaValue( context, options, value ) local image = value; local caption, formattedCaption = getCaption( context, options ) if not string.find( value, '[%[%]%{%}]' ) and not string.find( value, 'UNIQ%-%-imagemap' ) then -- если в value не содержится викикод или imagemap, то викифицируем имя файла -- ищем слово imagemap в строке, потому что вставляется плейсхолдер: [[PHAB:T28213]] image = '[[File:' .. value .. '|frameless'; if options[ 'border' ] and options[ 'border' ] ~= '' then image = image .. '|border'; end local size = options[ 'size' ]; if size and size ~= '' then if not string.match( size, 'px$' ) and not string.match( size, 'пкс$' ) -- TODO: использовать перевод для языка вики then size = size .. 'px' end -- временно if string.match( size, 'pxpx' ) then image = '[[Категория:Википедия:Изображение с pxpx в размере]]' .. image end else size = fileDefaultSize; end image = image .. '|' .. size; if options[ 'alt' ] and options[ 'alt' ] ~= '' then image = image .. '|alt=' .. options[ 'alt' ]; end if caption ~= '' then image = image .. '|' .. caption end image = image .. ']]'; if formattedCaption ~= '' then image = image .. '<br>' .. formattedCaption; end else image = image .. formattedCaption .. getCategoryByCode( 'media-contains-markup' ); end if options.entity and options.fixdouble then local page = mw.title.getCurrentTitle() local txt = page:getContent() if txt and txt:match(':' .. value) and mw.title.getCurrentTitle():inNamespace(0) then if options.frame:preprocess('{{REVISIONID}}') == '' then image = image .. '<span class="error">Это изображение встречается ниже по тексту статьи; пожалуйста, уберите одну из копий (не потеряв при этом подпись)</span>' end image = image .. getCategoryByCode( 'media-contains-local-double' ) end end return image end return p ec384e72491465f4103cce95a8f9467df428a432 Модуль:Infocards 828 55 108 107 2025-01-25T21:00:25Z Vallenland 2 1 версия импортирована Scribunto text/plain local infocards = {} local calculateAge = true local dateCat = require( 'Module:Infocards/dateCat' ) local moduleDates = require( 'Module:Dates' ) --[[ Helper function that populates the argument list given that user may need to use a mix of named and unnamed parameters. This is relevant because named parameters are not identical to unnamed parameters due to string trimming, and when dealing with strings we sometimes want to either preserve or remove that whitespace depending on the application. ]] function infocards._getParameters( frame_args, arg_list ) local new_args = {} local index = 1 local value for i,arg in ipairs( arg_list ) do value = frame_args[arg] if value == nil then value = frame_args[index] index = index + 1 end new_args[arg] = value end return new_args end function infocards.isBlank( someString ) return someString == nil or mw.ustring.match(someString, '^%s*$') ~= nil end function infocards.isDate ( frame ) local new_args = infocards._getParameters( frame.args, {'s', 't', 'f'} ) local s = new_args['s'] or '' local t = new_args['t'] or '' local f = new_args['f'] or '' local result = infocards.isDateImpl ( s ) if (result) then return t else return f end end function infocards.isDateImpl ( s ) local converted = infocards.convertToDate ( s ) return converted ~= nil end function infocards.dateOfBirth( frame ) local new_args = infocards._getParameters( frame.args, {'dateOfBirth', 'dateOfDeath', 'suppressAge', 'nocat'} ) local dateOfBirth = new_args['dateOfBirth'] or '' local dateOfDeath = new_args['dateOfDeath'] or '' local suppressAge = new_args['suppressAge'] or '' local nocat = new_args['nocat'] or mw.title.getCurrentTitle().nsText return infocards.dateOfBirthImpl( dateOfBirth, dateOfDeath, suppressAge, nocat ) end function infocards.dateOfBirthImpl( dateOfBirth, dateOfDeath, suppressAge, nocat ) local appendToCategory = infocards.isBlank( nocat ) if ( infocards.isBlank( dateOfBirth ) ) then if ( appendToCategory ) then return dateCat.categoryNoBirthDate else return '' end end if ( mw.ustring.match( dateOfBirth, '^%s*неизвестн.%s*$' ) ~= nil or mw.ustring.match( dateOfBirth, '^%s*%?%s*$' ) ~= nil ) then if ( appendToCategory ) then return "''неизвестно''" .. dateCat.categoryUnknownBirthDate else return "''неизвестно''" end end local appendAge = not (suppressAge ~= '' or not calculateAge) and infocards.isBlank( dateOfDeath ) local parsedDate = infocards.convertToDate ( dateOfBirth ) if ( parsedDate == nil ) then --[[ Temporary hack in order to enable export dates to wikidata ]] local bDateStart = '<span class="no-wikidata" data-wikidata-property-id="P569">' local bDateEnd = '</span>' if ( appendToCategory ) then return bDateStart .. dateOfBirth .. bDateEnd .. dateCat.categoryManualWikification else return bDateStart .. dateOfBirth .. bDateEnd end end local result = infocards.formatDateImpl ( parsedDate, 'bday', appendToCategory and 'Родившиеся' or nil ) if ( appendAge ) then -- TODO: месяцы и дни для (нескольких) новорождённых (см. новейшие [[Категория:Родившиеся в ГГГГ году]]) local age = infocards.age ( parsedDate, os.date("*t") ) if ( age and age < 125) then result = result .. ' <span class="nowrap">(' .. age .. ' ' .. mw.language.new( 'ru' ):plural( age, 'год', 'года', 'лет') .. ')</span>' end if ( appendToCategory ) then if (not age and parsedDate and parsedDate.year ) then age = os.date('*t').year - parsedDate.year -- при неточной дате end if ( age ) then if ( age > 115 ) then result = result .. dateCat.categoryBigCurrentAge elseif ( age >= 0 ) then result = result .. dateCat.categoryBiographiesOfLivingPersons else result = result .. dateCat.categoryNegativeAge end end end end return result end function infocards.dateOfDeath( frame ) local new_args = infocards._getParameters( frame.args, {'dateOfBirth', 'dateOfDeath', 'nocat'} ) local dateOfBirth = new_args['dateOfBirth'] or '' local dateOfDeath = new_args['dateOfDeath'] or '' local nocat = new_args['nocat'] or mw.title.getCurrentTitle().nsText return infocards.dateOfDeathImpl( dateOfBirth, dateOfDeath, nocat ) end function infocards.dateOfDeathImpl( dateOfBirth, dateOfDeath, nocat ) if ( infocards.isBlank( dateOfDeath ) ) then return '' end local appendToCategory = infocards.isBlank( nocat ) if ( mw.ustring.match( dateOfDeath, '^%s*неизвестн.%s*$' ) ~= nil or mw.ustring.match( dateOfDeath, '^%s*%?%s*$' ) ~= nil ) then if ( appendToCategory ) then return "''неизвестно''" .. dateCat.categoryUnknownDeathDate else return "''неизвестно''" end end local parsedDateOfBirth = infocards.convertToDate ( dateOfBirth ) local parsedDateOfDeath = infocards.convertToDate ( dateOfDeath ) if ( parsedDateOfDeath == nil ) then --[[ Temporary hack in order to enable export dates to wikidata ]] local dDateStart = '<span class="no-wikidata" data-wikidata-property-id="P570">' local dDateEnd = '</span>' if ( appendToCategory ) then return dDateStart .. dateOfDeath .. dDateEnd .. dateCat.categoryManualWikification else return dDateStart .. dateOfDeath .. dDateEnd end end local result = infocards.formatDateImpl ( parsedDateOfDeath, 'dday', appendToCategory and 'Умершие' or nil ) if ( calculateAge ) then local age = infocards.age ( parsedDateOfBirth, parsedDateOfDeath ) if ( age and age > 0 ) then result = result .. ' <span class="nowrap">(' .. age .. ' ' .. mw.language.new( 'ru' ):plural( age, 'год', 'года', 'лет') .. ')</span>' end -- returns category to recently deceased persons local unixAvailable, unixDateOfDeath = pcall(function() local r = os.time(parsedDateOfDeath) if ( r ~= os.time() ) then return r end error() end) if (appendToCategory) then if ( unixAvailable and os.time() - unixDateOfDeath < 31536000 ) then result = result .. dateCat.categoryRecentlyDeceased elseif (age and age < 0) then result = result .. dateCat.categoryNegativeAge end end end return result end function infocards.age( parsedBirthDate, parsedFinishDate ) if ( parsedBirthDate == nil or parsedFinishDate == nil ) then return nil end local bd = parsedBirthDate["day"] local bm = parsedBirthDate["month"] local by = parsedBirthDate["year"] local dd = parsedFinishDate["day"] local dm = parsedFinishDate["month"] local dy = parsedFinishDate["year"] if ( bd and bm and by and dd and dm and dy ) then if ( dm > bm or ( dm == bm and dd >= bd ) ) then return dy - by else return dy - by - 1 end else return nil end end function infocards.formatDateImpl( parsedDate, infocardClass, categoryNamePrefix ) local datePart = '<span class="nowrap">' --Temporary hack in order to enable export dates to wikidata if infocardClass == "bday" then datePart = '<span class="no-wikidata" data-wikidata-property-id="P569">' elseif infocardClass == "dday" then datePart = '<span class="no-wikidata" data-wikidata-property-id="P570">' end local t1 = { day = parsedDate.osday, month = parsedDate.osmonth, year = parsedDate.osyear } local t2 = { day = parsedDate.day, month = parsedDate.month, year = parsedDate.year } datePart = datePart .. moduleDates.formatWikiImpl( t1, t2, infocardClass, categoryNamePrefix ) datePart = datePart .. '</span>' return datePart end function infocards.convertToDate( possibleDateString ) possibleDateString = mw.ustring.gsub( possibleDateString, '−', '-') local simpleDate = mw.ustring.match(possibleDateString, '^%s*([%-%d%.]+)%s*$', 0) if ( simpleDate ) then return infocards.convertToDateNewStylePart( simpleDate ) end local complexDate1, complexDate2 = mw.ustring.match(possibleDateString, '^%s*([%-%d%.]+)%s*%(([%-%d%.]+)%)%s*$', 0) if ( complexDate1 and complexDate2) then local table1 = infocards.convertToDateNewStylePart( complexDate1 ) local table2 = infocards.convertToDateOldStylePart( complexDate2 ) if ( table1 and table2 ) then return { year = table1["year"], month = table1["month"], day = table1["day"], osyear = table2["year"], osmonth = table2["month"], osday = table2["day"] } else return nil end end return nil end function infocards.convertToDateNewStylePart( possibleDateString ) local ny = mw.ustring.match(possibleDateString, '^(%-?%d+)$', 0) if (ny ~= nil) then return {year = tonumber(ny)} end return infocards.convertToDateCommonPart( possibleDateString ) end function infocards.convertToDateOldStylePart( possibleDateString ) local nd = mw.ustring.match(possibleDateString, '^(%-?%d+)$', 0) if (nd ~= nil) then return {day = tonumber(nd)} end return infocards.convertToDateCommonPart( possibleDateString ) end function infocards.convertToDateCommonPart( possibleDateString ) local sDay, sMonth, sYear local day, month, year sDay, sMonth, sYear = mw.ustring.match( possibleDateString, '^(%d?%d)%.(%d?%d)%.(%-?%d+)$', 0 ) if sDay ~= nil and sMonth ~= nil and sYear ~= nil then day = tonumber( sDay ) month = tonumber( sMonth ) year = tonumber( sYear ) if day >= 1 and day <= 32 and month >= 1 and month <= 12 then return { day = day, month = month, year = year } end end sDay, sMonth = mw.ustring.match( possibleDateString, '^(%d?%d)%.(%d?%d+)$', 0 ) if sDay ~= nil and sMonth ~= nil then day = tonumber( sDay ) month = tonumber( sMonth ) if day >= 1 and day <= 32 and month >= 1 and month <= 12 then return { day = day, month = month } end end sMonth, sYear = mw.ustring.match( possibleDateString, '^(%d?%d)%.(%-?%d+)$', 0 ) if sMonth ~= nil and sYear ~= nil then month = tonumber( sMonth ) year = tonumber( sYear ) if month >= 1 and month <= 12 then return { month = month, year = year } end end return nil end return infocards 6c1e746d6605d4d101f6aa9fd3e4824b60c64ef7 Модуль:Infocards/dateCat 828 56 110 109 2025-01-25T21:00:25Z Vallenland 2 1 версия импортирована Scribunto text/plain local p = {} p.categoryUnknownBirthDate = '[[Категория:Персоналии, чья дата рождения не установлена]]' p.categoryUnknownDeathDate = '[[Категория:Персоналии, чья дата смерти не установлена]]' p.categoryBigCurrentAge = '[[Категория:Персоналии с большим текущим возрастом]]' --бывш. [[Категория:Википедия:Статьи о персоналиях с большим текущим возрастом]] p.categoryNegativeAge = '[[Категория:Персоналии с отрицательным возрастом]]' -- p.categoryBigDeathAge = '[[Категория:Википедия:Статьи о персоналиях с большим возрастом во время смерти]]' //deleted -d.bratchuk 05-07-2016 p.categoryBiographiesOfLivingPersons = '[[Категория:Википедия:Биографии современников]]' p.categoryRecentlyDeceased = '[[Категория:Персоналии, умершие менее года назад]]' p.categoryManualWikification = '[[Категория:Википедия:Статьи с ручной викификацией дат в карточке]]' p.categoryNoBirthDate = '[[Категория:Персоналии без указанной даты рождения]]' --бывш. [[Категория:Википедия:Персоны без указанной даты рождения]] return p 6b27e44bc0a4aaafa42074ca16db92b13e4999d4 Модуль:Wikidata/Interproject 828 57 112 111 2025-01-25T21:00:26Z Vallenland 2 1 версия импортирована Scribunto text/plain local p = {} function p.getWikivoyageLink( context ) return p.getSisterProjectLink( 'voy', 'wikivoyage', context ) end function p.getWikibooksLink( context ) return p.getSisterProjectLink( 'b', 'wikibooks', context ) end function p.getWikiquoteLink( context ) return p.getSisterProjectLink( 'q', 'wikiquote', context ) end function p.getWikisourceLink( context ) return p.getSisterProjectLink( 's', 'wikisource', context ) end function p.getWikipediaLink( context ) return p.getSisterProjectLink( 'w', 'wiki', context ) end function p.getWiktionaryLink( context ) return p.getSisterProjectLink( 'wikt', 'wiktionary', context ) end function p.getSisterProjectLink( projectInterwikiPrefix, projectName, context ) -- проброс параметра from откуда угодно local entityId = nil local p_context = context while p_context do if p_context.args and p_context.args.from and p_context.args.from ~= '' then if p_context.args.from == '-' then return '' end entityId = p_context.args.from else entityId = mw.wikibase.getEntityIdForCurrentPage() end p_context = p_context:getParent() end -- По умолчанию старается достать ссылку на русском, иначе - на родном (P103) local wbStatus, sitelink = pcall( mw.wikibase.getSitelink, entityId, 'ru' .. projectName ) if wbStatus and sitelink then return projectInterwikiPrefix .. ':' .. sitelink end local wbStatus, langClaims = pcall( mw.wikibase.getBestStatements, entityId, 'P103' ) if wbStatus ~= true or not langClaims then return '' end local codes = mw.loadData( 'Module:Wikidata:Dictionary/P424' ) for _, claim in ipairs( langClaims ) do if claim.mainsnak and claim.mainsnak.datavalue and claim.mainsnak.datavalue.value and claim.mainsnak.datavalue.value.id then local codesById = codes[ claim.mainsnak.datavalue.value.id ] if codesById then for _, code in ipairs( codesById ) do wbStatus, sitelink = pcall( mw.wikibase.getSitelink, entityId, code .. projectName ) if wbStatus and sitelink then return projectInterwikiPrefix .. ':' .. code .. ':' .. sitelink end end end end end return '' end return p 48f3bdd682abd29718705f19e0411be2db6490cd Модуль:String2 828 58 114 113 2025-01-25T21:00:26Z Vallenland 2 1 версия импортирована Scribunto text/plain --[[ Кое-какие дополнительные функции для строк ]] local M = { bs=function(f)-- первый параметр до начала второго параметра (или до конца, если он не встретился) --необяз. 3-й параметр - с какого по номеру (с 1) символа начинать поиск. return mw.ustring.sub(f.args[1], 1, (mw.ustring.find(f.args[1],f.args[2],tonumber(f.args[3] or 1),true) or 0)-1) end; as=function(f)-- первый параметр после начала второго параметра return mw.ustring.sub(f.args[1], (mw.ustring.find(f.args[1],f.args[2],1,true) or 0)+1) end; Tr=function(s,f,t,cf,df,sf)-- транслитерация первого параметра путём замены символов из второго параметра символами из третьего. -- Отдельными параметрами можно передавать флаги c, d и s, как в Perl; диапазоны в замене не работают, только в левой части -- (т.е. дефис надо передавать первым или последним). Второй результат - число заменённых символов local r, l, l2 = {}, mw.ustring.len(f), mw.ustring.len(t); for i = 1, l do r[mw.ustring.sub(f,i,i)] = i<=l2 and mw.ustring.sub(t,i,i) or df and '' or mw.ustring.sub(t,l2,l2) end local n2=0; local res, n = mw.ustring.gsub( s, ('[%s%s]%s'):format( cf and '^' or '', f:gsub('%','%%'):gsub(']','%]'):gsub('^%^','%^'), sf and '+' or '' ), sf and function(cc) n2 = n2+mw.ustring.len(cc)-1; return mw.ustring.gsub(cc,'.',r) end or r ) return res, n+n2 end; -- tr = function(f) return (M.Tr(f.args[1],f.args[2],f.args[3],f.args['c'],f.args['d'],f.args['s'])) end;-- транслитерировать -- trс = function(f) return ({M.Tr(f.args[1],f.args[2],f.args[3],f.args['c'],f.args['d'],f.args['s'])})[2] end;-- посчитать символы Trg = function(s,t,f,fi)-- Производит замену строк произвольной длины (если с fi, регистр не учитывает). -- Приоритет - по порядку в таблицах. for n,p in ipairs(t) do t[n] = {fi and mw.ustring.upper(p) or p,mw.ustring.len(p)} end local r,i,l,N = {},1,mw.ustring.len(s),0 while i<=l do (function() for n,p in ipairs(t) do if ( fi and mw.ustring.upper(mw.ustring.sub(s,i,i+p[2]-1)) or mw.ustring.sub(s,i,i+p[2]-1) ) == p[1] then table.insert(r,f[n]); i = i+p[2]; N=N+1; return end end table.insert(r,mw.ustring.sub(s,i,i)); i=i+1; return end)() end return table.concat(r),N end; trg = function(frame)--Работает с номерными аргументами шаблона,если задан параметр u, иначе со своими. -- Заменяет в первом аргументе аргументы 2, 4, 6... на аргументы 3, 5, 7... local tf, t, f, i= frame.args['u'] and frame.getParent() or f, {}, {}, 1; while tf.args[2*i] do t[tf.args[2*i]]=tf.args[2*i+1] or '' end return ( M.Trg(tf.args[1],t,f,(frame.args['i'] or '')~='') ) end; join = function (f) --объединяет нумерованные аргументы вызвавшего шаблона -- от from или 1 до to или первого отсутствующего -- через первый параметр invoke. Последний элемент можно присоединять иначе, задав второй параметр. -- По умолчанию ',' & 'и' -- Если 3-й параметр invoke — "s", строки из пробелов игнорируются; если "_", игнорируются пустые строки local t, tf, i = {}, f:getParent(), tonumber(f.args.from) or 1 local k,j,m = tonumber(f.args.to),i,f.args[3] while k and i<=k or tf.args[i] do if ( ({ ['_']=function(s)return s~=''end; ['s']=function(s)return not tostring(s):match("^%s*$")end })[m] or function() return true end )(tf.args[i]) then t[j]=tf.args[i]; j=j+1 end; i=i+1 end return mw.text.listToText(t,f.args[1],f.args[2] or f.args[1]) end } function M.formatRound(frame) --форматирует число, чтобы оно имело order знаков после запятой return string.format("%0."..frame.args[2].."f",tonumber(frame.args[1])); end -- если строка s содержит число, увеличивает первое такое число на n, иначе возращает пустую строку. -- если число начинается на 0, то увеличенное число будет содержать по крайне мере столько цифр сколько исходное. function M.increase(s, n) local a,b,c = string.match(s, "([^0-9]*)([0-9]+)(.*)") if b==nil then return s end local num = tonumber(b) + n if b:sub(1,1)=='0' then b = string.format("%0"..b:len().."d", num) else b=num end return a .. b .. c end function M.ucfirst(frame ) local s = mw.text.trim( frame.args[1] or "" ) local s1 = "" -- if it's a list chop off and (store as s1) everything up to the first <li> local lipos = string.find(s, "<li>" ) if lipos then s1 = string.sub(s, 1, lipos + 3) s = string.sub(s, lipos + 4) end -- s1 is either "" or the first part of the list markup, so we can continue -- and prepend s1 to the returned string local letterpos if string.find(s, "^%[%[[^|]+|[^%]]+%]%]") then -- this is a piped wikilink, so we capitalise the text, not the pipe local _ _, letterpos = string.find(s, "|%A*%a") -- find the first letter after the pipe else letterpos = string.find(s, '%a') end if letterpos then local first = string.sub(s, 1, letterpos - 1) local letter = string.sub(s, letterpos, letterpos) local rest = string.sub(s, letterpos + 1) return s1 .. first .. string.upper(letter) .. rest else return s1 .. s end end return M 1d51eb45a573b689485dad672c0968c18ec3b342 Модуль:Wikidata/date 828 59 116 115 2025-01-25T21:00:27Z Vallenland 2 1 версия импортирована Scribunto text/plain --settings local nowLabel = 'наст.&nbsp;время' local moduleDates = require( "Module:Dates" ) local moduleWikidata = require( "Module:Wikidata" ) local dateCat = require("Module:Infocards/dateCat") -- FIXME: undeclared global variable, used 3 times local infoclass local function deepcopy(orig) local orig_type = type(orig) local copy if orig_type == 'table' then copy = {} for orig_key, orig_value in next, orig, nil do copy[deepcopy(orig_key)] = deepcopy(orig_value) end setmetatable(copy, deepcopy(getmetatable(orig))) else -- number, string, boolean, etc copy = orig end return copy end local function ageImpl ( bStructure, bPrecision, dStructure, dPrecision ) if ( not bStructure or not dStructure or bPrecision < 10 or dPrecision < 10 ) then return nil end local shift = 0 if ( bStructure.year < 0 and dStructure.year > 0 ) then shift = -1 end if ( bPrecision == 10 or dPrecision == 10 ) then if ( bStructure.month < dStructure.month ) then return dStructure.year - bStructure.year + shift end if ( bStructure.month == dStructure.month ) then return nil end if ( bStructure.month > dStructure.month ) then return dStructure.year - bStructure.year - 1 + shift end end if ( bStructure.month < dStructure.month ) then return dStructure.year - bStructure.year + shift end if ( bStructure.month == dStructure.month ) then if ( bStructure.day <= dStructure.day ) then return dStructure.year - bStructure.year + shift else return dStructure.year - bStructure.year - 1 + shift end end if ( bStructure.month > dStructure.month ) then return dStructure.year - bStructure.year - 1 + shift end return nil end -- accepts table of time+precision values local function ageCurrent ( bTable ) local possibleAge = "NYA" -- it means "Not Yet Assigned", not what you imagined! for bKey, bValue in pairs(bTable) do if ( bValue.unknown ) then return nil end local bStructure = bValue.structure local bPrecision = bValue.precision local dStructure = os.date( "*t" ) local calculatedAge = ageImpl ( bStructure, bPrecision, dStructure, 11 ) if ( possibleAge == "NYA" ) then possibleAge = calculatedAge else if ( possibleAge ~= calculatedAge ) then possibleAge = nil end end end return possibleAge end -- accepts tables of time+precision values local function age ( bTable, dTable ) local possibleAge = "NYA" -- it means "Not Yet Assigned", not what you imagined! for bKey, bValue in pairs( bTable ) do if ( bValue.unknown ) then return nil end local bStructure = bValue.structure local bPrecision = bValue.precision for dKey, dValue in pairs( dTable ) do if ( dValue.unknown ) then return nil end local dStructure = dValue.structure local dPrecision = dValue.precision if ( bValue.calendar == 'julian' and dValue.calendar == 'gregorian' ) then -- to calculate age, need to adjust bStructure to gregorian calendar local shift = math.floor(bStructure.year/100-2) - math.floor(bStructure.year/400) -- TODO: re-implement this properly bStructure.day = bStructure.day + shift end local calculatedAge = ageImpl ( bStructure, bPrecision, dStructure, dPrecision ) if ( possibleAge == "NYA" ) then possibleAge = calculatedAge else if ( possibleAge ~= calculatedAge ) then possibleAge = nil end end end end return possibleAge end local function parseISO8601Date(str) local pattern = "(%-?%d+)%-(%d+)%-(%d+)T" local Y, M, D = mw.ustring.match( str, pattern ) return tonumber(Y), tonumber(M), tonumber(D) end local function parseISO8601Time(str) local pattern = "T(%d+):(%d+):(%d+)%Z" local H, M, S = mw.ustring.match( str, pattern) return tonumber(H), tonumber(M), tonumber(S) end local function parseISO8601Offset(str) if str:sub(-1)=="Z" then return 0,0 end -- ends with Z, Zulu time -- matches ±hh:mm, ±hhmm or ±hh; else returns nils local pattern = "([-+])(%d%d):?(%d?%d?)$" local sign, oh, om = mw.ustring.match( str, pattern) sign, oh, om = sign or "+", oh or "00", om or "00" return tonumber(sign .. oh), tonumber(sign .. om) end local function parseISO8601(str) if 'table' == type(str) then if str.args and str.args[1] then str = '' .. str.args[1] else return 'unknown argument type: ' .. type( str ) .. ': ' .. table.tostring( str ) end end local Y,M,D = parseISO8601Date(str) local h,m,s = parseISO8601Time(str) local oh,om = parseISO8601Offset(str) if not Y or not M or not D or not h or not m or not s or not oh or not om then return nil end return tonumber(os.time({year=Y, month=M, day=D, hour=(h+oh), min=(m+om), sec=s})) end local function parseClaim ( claim ) if ( claim.mainsnak.snaktype == "value" ) then local timeISO8601 = string.gsub( string.gsub( tostring( claim.mainsnak.datavalue.value.time ), '-00%-', '-01-' ), '-00T', '-01T' ) local unixtime = parseISO8601( timeISO8601 ) local structure = os.date("*t", unixtime) local precision = tonumber( claim.mainsnak.datavalue.value.precision ) local calendarmodel = 'gregorian' if (mw.ustring.find(claim.mainsnak.datavalue.value.calendarmodel, 'Q1985786', 1, true)) then calendarmodel = 'julian' end local item = { structure=structure, precision=precision, calendar = calendarmodel } return item elseif ( claim.mainsnak.snaktype == "novalue" ) then -- novalue return { unknown="novalue" } else --unknown return { unknown="unknown" } end end -- returns table of time+precision values for specified property local function parseProperty ( context, options, propertyId ) if ( not context ) then error( 'context not specified'); end if ( not options ) then error( 'options not specified'); end if ( not options.entity ) then error( 'options.entity is missing'); end if ( not propertyId ) then error( 'propertyId not specified'); end local claims = context.selectClaims( options, propertyId ) if not claims then return nil end local result = {} for key, claim in pairs( claims ) do table.insert ( result, parseClaim( claim ) ) end return result end -- проверка на совпадающие даты с разной моделью календаря local function checkDupDates( t ) if #t > 1 then local removed = false local j = 1 -- проверка на совпадающие даты с разной моделью календаря while (j <= #t) do local i = 1 while (i <= #t) do if i ~= j then if (os.time(t[j].structure) == os.time(t[i].structure)) then if ((t[j].calendarmodel == 'gregorian') and (t[i].calendarmodel == 'julian')) then removed = true break else table.remove(t, i) end else i = i + 1 end else i = i + 1 end end if removed then removed = false table.remove(t, j) else j = j+1 end end end end -- returns first qualifier of specified propertyId local function getQualifierWithDataValue( statement, qualifierPropertyId ) if ( statement.qualifiers and statement.qualifiers[qualifierPropertyId] ) then local qualifiers = statement.qualifiers[qualifierPropertyId] for _, qualifier in ipairs( qualifiers ) do if (qualifier.datavalue) then return qualifier end end end return nil end local p = {} local function formatDecade( time, categoryNamePrefix ) local bce = '' local year if time.year < 0 then bce = ' до н. э.' year = math.floor( math.abs( time.year ) / 10 ) * 10 else year = math.floor( time.year / 10 ) * 10 end local unit = '-е' if isGenitive then unit = '-х' end local value = '' .. year .. unit .. bce if categoryNamePrefix then return value .. '[[Category:' .. categoryNamePrefix .. ' в ' .. year .. '-е годы' .. bce .. ']]' end return value end local function formatCentury( time, categoryNamePrefix, isGenitive ) local moduleRoman = require( 'Module:RomanNumber' ) local bce = '' local century if time.year < 0 then bce = ' до н. э.' century = math.floor( ( math.abs( time.year ) - 1 ) / 100 ) + 1 else century = math.floor( ( time.year - 1 ) / 100 ) + 1 end local unit = 'век' if isGenitive then unit = 'века' end local infix = ' в ' if century == 2 then infix = ' во ' end if moduleRoman then century = moduleRoman.toRomanNumber( century ) end local value = '[[' .. century .. ' век' .. bce .. '|' .. century .. ' ' .. unit .. bce .. ']]' if categoryNamePrefix then return value .. '[[Category:' .. categoryNamePrefix .. infix .. century .. ' веке' .. bce .. ']]' end return value end local function formatMillenium( time, categoryNamePrefix, isGenitive ) local bce = '' local millenium if time.year < 0 then bce = ' до н. э.' millenium = math.floor( ( math.abs( time.year ) - 1 ) / 1000 ) + 1 else millenium = math.floor( ( time.year - 1 ) / 1000 ) + 1 end local unit = '-е тысячелетие' if isGenitive then unit = '-го тысячелетия' end local value = '[[' .. millenium .. '-е тысячелетие' .. bce .. '|' .. millenium .. unit .. bce .. ']]' if categoryNamePrefix then local infix = ' в ' if millenium == 2 then infix = ' во ' end return value .. '[[Category:' .. categoryNamePrefix .. infix .. millenium .. '-м тысячелетии' .. bce .. ']]' else return value end end local function formatDateImpl( value, options, microformatClass, categoryPrefix, leftBracket, rightBracket, nolinks, isGenitive ) if ( not value ) then error( 'value not specified'); end if ( not options ) then error( 'options not specified'); end -- The calendar model used for saving the data is always the proleptic Gregorian calendar according to ISO 8601. local timeISO8601 = string.gsub( string.gsub( tostring( value.time ), '-00%-', '-01-' ), '-00T', '-01T' ) local unixtime = parseISO8601( timeISO8601 ) if not unixtime then return '' end local structure = os.date("*t", unixtime) local precision = tonumber( value.precision ) if precision <= 6 then return formatMillenium( structure, categoryPrefix, isGenitive ) end if precision == 7 then return formatCentury( structure, categoryPrefix, isGenitive ) end if precision == 8 then return formatDecade( structure, categoryPrefix, isGenitive ) end if precision == 9 then local tCopy = deepcopy( structure ) tCopy.day = nil tCopy.month = nil return moduleDates.formatWikiImpl( tCopy, tCopy, infoclass, categoryPrefix, leftBracket, rightBracket, nolinks ) end -- year and month only if precision == 10 then local tCopy = deepcopy( structure ) tCopy.day = nil return moduleDates.formatWikiImpl( tCopy, tCopy, infoclass, categoryPrefix, leftBracket, rightBracket, nolinks ) end local calendarmodel = 'gregorian' if (mw.ustring.find(value.calendarmodel, 'Q1985786', 1, true)) then calendarmodel = 'julian' end if (calendarmodel == 'gregorian') then return moduleDates.formatWikiImpl( structure, structure, microformatClass, categoryPrefix, leftBracket, rightBracket, nolinks ) else return p.formatAsJulian( timeISO8601, infoclass, categoryPrefix, leftBracket, rightBracket, nolinks ) end end local function formatApproximateDateClaim( context, options, statement, unknownDateCategory ) if ( not context ) then error( 'context not specified'); end if ( not options ) then error( 'options not specified'); end if ( not options.entity ) then error( 'options.entity is missing'); end if ( not statement ) then error( 'statement not specified'); end if options.nocat then unknownDateCategory = "" end local qNotSoonerThan = getQualifierWithDataValue( statement, 'P1319' ) local qNotLaterThan = getQualifierWithDataValue( statement, 'P1326' ) if ( qNotSoonerThan or qNotLaterThan ) then local results = {} if ( qNotSoonerThan ) then local formattedDate = formatDateImpl( qNotSoonerThan.datavalue.value, {}, nil, nil, options.leftBracket, options.rightBracket, options.nolinks, true ) local value = 'не&nbsp;ранее&nbsp;' .. context.wrapSnak( formattedDate, qNotSoonerThan.hash ) table.insert( results, context.wrapQualifier( value, 'P1319' ) ) end if ( qNotLaterThan ) then local formattedDate = formatDateImpl( qNotLaterThan.datavalue.value, {}, nil, nil, options.leftBracket, options.rightBracket, options.nolinks, true ) local value = 'не&nbsp;позднее&nbsp;' .. context.wrapSnak( formattedDate, qNotLaterThan.hash ) table.insert( results, context.wrapQualifier( value, 'P1326' ) ) end return mw.text.listToText( results, ' и ' , ' и ' ) .. unknownDateCategory .. context.formatRefs( options, statement ) end return nil end function p.formatDateOfBirthClaim( context, options, statement ) local value = formatApproximateDateClaim( context, options, statement, dateCat.categoryUnknownBirthDate ) if value then return value end options['conjunction'] = '&#32;или&#32;' options['value-module'] = 'Wikidata/date' options['value-function'] = 'formatBirthDate' options.i18n.somevalue = '\'\'неизвестно\'\'' .. dateCat.categoryUnknownBirthDate local circumstances = context.getSourcingCircumstances( statement ) for _, itemId in ipairs( circumstances ) do if itemId == 'Q5727902' then options.isGenitive = true break end end local result = context.formatStatementDefault( context, options, statement ) local bTable = { parseClaim( statement ) } local dTable = parseProperty ( context, options, 'P570' ) if ( bTable and not dTable ) then local age = ageCurrent( bTable ) if ( age ) then if ( options.suppressAge == nil or options.suppressAge == '' ) then result = result .. ' <span style="white-space:nowrap;">(' .. age .. ' ' .. mw.language.new( 'ru' ):plural( age, 'год', 'года', 'лет') .. ')</span>' end if ( not options.nocat ) then if ( age > 115 ) then result = result .. dateCat.categoryBigCurrentAge elseif (age >= 0) then result = result .. dateCat.categoryBiographiesOfLivingPersons else result = result .. dateCat.categoryNegativeAge end end end end return result end function p.formatDateOfDeathClaim( context, options, statement ) local value = formatApproximateDateClaim( context, options, statement, dateCat.categoryUnknownDeathDate ) if value then return value end options['conjunction'] = '&#32;или&#32;' options['value-module'] = 'Wikidata/date' options['value-function'] = 'formatDeathDate' options.i18n.somevalue = '\'\'неизвестно\'\'' .. dateCat.categoryUnknownDeathDate local circumstances = context.getSourcingCircumstances( statement ) for _, itemId in ipairs( circumstances ) do if itemId == 'Q5727902' then options.isGenitive = true break end end local result = context.formatStatementDefault( context, options, statement ) local bTable = parseProperty ( context, options, 'P569' ) local dTable = { parseClaim( statement ) } if ( bTable and dTable ) then local age = age( bTable, dTable ) if ( age ) then if ( options.suppressAge == nil or options.suppressAge == '' ) then result = result .. ' <span style="white-space:nowrap;">(' .. age .. ' ' .. mw.language.new( 'ru' ):plural( age, 'год', 'года', 'лет') .. ')</span>' end if ( not options.nocat and age < 0) then result = result .. dateCat.categoryNegativeAge end end -- returns category to recently deceased persons local unixAvailable, unixDateOfDeath = pcall(function() local r = os.time(dTable[1].structure) if ( r ~= os.time() ) then return r end error() end) if ( unixAvailable and os.time() - unixDateOfDeath < 31536000 and not options.nocat ) then result = result .. dateCat.categoryRecentlyDeceased end end return result end -- Reentry point for Wikidata Snak formatting function p.formatBirthDate( context, options, value ) if ( not context ) then error( 'context not specified'); end if ( not options ) then error( 'options not specified'); end if ( not value ) then error( 'value not specified'); end local microformatClass = nil if options.microformat ~= '-' then microformatClass = options.microformat or 'bday' end if ( options.nocat ) then return formatDateImpl( value, options, microformatClass, nil, options.leftBracket, options.rightBracket, options.nolinks, options.isGenitive ) else return formatDateImpl( value, options, microformatClass, 'Родившиеся', options.leftBracket, options.rightBracket, options.nolinks, options.isGenitive ) end end -- Reentry point for Wikidata Snak formatting function p.formatDeathDate( context, options, value ) if ( not context ) then error( 'context not specified'); end if ( not options ) then error( 'options not specified'); end if ( not value ) then error( 'value not specified'); end local microformatClass = nil if options.microformat ~= '-' then microformatClass = options.microformat or 'dday' end if ( options.nocat and options.nocat ~= '' ) then return formatDateImpl( value, options, microformatClass, nil, options.leftBracket, options.rightBracket, options.nolinks, options.isGenitive ) else return formatDateImpl( value, options, microformatClass, 'Умершие', options.leftBracket, options.rightBracket, options.nolinks, options.isGenitive ) end end -- Reentry point for Wikidata Snak formatting -- default one function p.formatDate( context, options, value ) if ( not context ) then error( 'context not specified'); end if ( not options ) then error( 'options not specified'); end if ( not value ) then error( 'value not specified'); end local microformatClass = options.microformat or nil if ( options.nocat and options.nocat ~= '' ) then return formatDateImpl( value, options, microformatClass, nil, options.leftBracket, options.rightBracket, options.nolinks, options.isGenitive ) else local categoryPrefix = options.categoryPrefix or nil return formatDateImpl( value, options, microformatClass, categoryPrefix, options.leftBracket, options.rightBracket, options.nolinks, options.isGenitive ) end end function p.formatDateIntervalProperty( context, options ) if ( not context ) then error( 'context not specified' ); end if ( not options ) then error( 'options not specified' ); end if ( not options.entity ) then error( 'options.entity missing' ); end -- Получение нужных утверждений local WDS = require( 'Module:WikidataSelectors' ) local fromProperty = options.property if options.from and options.from ~= '' then fromProperty = options.from end local fromClaims = WDS.load( options.entityId, fromProperty ) local toClaims = WDS.load( options.entityId, options.to ) if fromClaims == nil and toClaims == nil then return '' end local formattedFromClaims = {} if fromClaims then for i, claim in ipairs( fromClaims ) do local formattedStatement = context.formatStatement( options, claim ) if formattedStatement then formattedStatement = '<span class="wikidata-claim" data-wikidata-property-id="' .. string.upper( options.property ) .. '" data-wikidata-claim-id="' .. claim.id .. '">' .. formattedStatement .. '</span>' table.insert( formattedFromClaims, formattedStatement ) end end end local formattedToClaims = {} local toOptions = deepcopy( options ) toOptions.property = options.to toOptions.novalue = nowLabel if toClaims then for i, claim in ipairs( toClaims ) do local formattedStatement = context.formatStatement( toOptions, claim ) if formattedStatement then formattedStatement = '<span class="wikidata-claim" data-wikidata-property-id="' .. string.upper( toOptions.property ) .. '" data-wikidata-claim-id="' .. claim.id .. '">' .. formattedStatement .. '</span>' table.insert( formattedToClaims, formattedStatement ) end end end local out = '' local fromOut = mw.text.listToText( formattedFromClaims, options.separator, options.conjunction ) local toOut = mw.text.listToText( formattedToClaims, options.separator, options.conjunction ) if fromOut ~= '' or toOut ~= '' then if fromOut ~= '' then out = fromOut else out = '?' end if toOut ~= '' then out = out .. ' — ' .. toOut else local withinClaims = nil if options.within then WDS.load( options.entityId, options.within ) end if withinClaims == nil then out = 'с ' .. out else out = out .. ' — ' .. nowLabel end end end if out ~= '' then if options.before then out = options.before .. out end if options.after then out = out .. options.after end end return out end local lowestBoundary = '1582-10-05T00:00:00Z' local lastBoundary = '1918-01-31T00:00:00Z' local boundaries = { -- from (G) till next will be diff(G = J + diff), at current { lowestBoundary, 10 }, { '1700-02-29T00:00:00Z', 11 }, { '1800-02-29T00:00:00Z', 12 }, { '1900-02-29T00:00:00Z', 13 }, { lastBoundary, '' }, } -- Передаваемое время обязано быть по Юлианскому календарю (старому стилю) function p.formatAsJulian( julTimeISO8601, infocardClass, categoryNamePrefix, leftBracket, rightBracket, nolinks ) if 'table' == type( julTimeISO8601 ) then if julTimeISO8601.args and julTimeISO8601.args[1] then julTimeISO8601 = julTimeISO8601.args[1] else return 'unknown argument type: ' .. type( julTime ) .. ': ' .. table.tostring( julTime ) end end julTimeISO8601 = mw.text.trim( julTimeISO8601 ) julTimeISO8601 = string.gsub( julTimeISO8601, '^+', '' ) local julTime = parseISO8601( julTimeISO8601 ) local t = os.date( "*t", julTime ) if ( julTime < parseISO8601( lowestBoundary ) ) then -- only julian if string.find( julTimeISO8601, '-02-29T', 1, true ) then t = { year = t.year, month = 2, day = 29 } end return moduleDates.formatWikiImpl( t, t, infocardClass, categoryNamePrefix, leftBracket, rightBracket, nolinks ) end if ( julTimeISO8601 >= lastBoundary ) then return "''некорректная дата (юлианский календарь не используется после 1918-01-26)''" end -- julian and grigorian for i = 1, #boundaries, 1 do local b1 = boundaries[i][1] local b2 = boundaries[i + 1][1] if ( b1 <= julTimeISO8601 and julTimeISO8601 < b2 ) then local diff = boundaries[i][2] if string.sub( julTimeISO8601, 1, 10 ) == string.sub( boundaries[i][1], 1, 10 ) then t = { year = t.year, month = 2, day = 29 } diff = diff - 1 end local gregTime = os.date( "*t", julTime + diff * 24 * 60 * 60 ) return moduleDates.formatWikiImpl( t, gregTime, infocardClass, categoryNamePrefix, leftBracket, rightBracket, nolinks ) end end return "''ошибка в модуле Модуль:Wikidata/date''" end return p 12c2c34efd103d2938bd65421aa550e8c6f26da0 Шаблон:Join 10 60 118 117 2025-01-25T21:00:27Z Vallenland 2 1 версия импортирована wikitext text/x-wiki {{<includeonly>safesubst:</includeonly>#invoke:Separated entries|main|separator={{{separator|}}}}}<noinclude> {{doc}} <!-- Категории — на подстраницу /doc, интервики — в Викиданные. --> </noinclude> 92bb17b5322d3ae0ceab93d4dad3d31810d47eb0 Модуль:Dates 828 61 120 119 2025-01-25T21:00:27Z Vallenland 2 1 версия импортирована Scribunto text/plain --[[ В это модуле собраны функции, связанные с работой с датами. ]] local monthg = {'января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', "сентября", "октября", "ноября", "декабря"} local monthd = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} local function DecodeDate(d)-- Ч, М, Г, СЧ, СМ, СГ, хвост --дата: "%-?%d+"=год, "%d+%.%d+"=число месяца, "%d+%.%d+%.%-?%d+"=ЧМГ, -- потом в скобках м.б. переопределено для старого стиля начиная с числа local nd=d:match("^[%d.-]*"); local od=d:match("^[%d.-]*%s*%(%s*([%d.-]*)%s*%)"); local tail = d:match("^[%d.-]+%s*%(%s*[%d.-]+%s*%)%s*(%S.*)") or d:match("^[%d.-]+%s*([^%s%d].*)"); if nd:match('^%-?%d+$' ) then return nil, nil, tonumber(nd), nil, nil, od and tonumber(od:match("%-?%d+$")),tail else local j,m,y=nd:match("^(%d+)%.(%d+)%.?(%-?%d*)"); if j then if od then local oj, om, oy = od:match("^(%d+)%.?(%d*)%.?(%-?%d*)"); return j and tonumber(j), m and tonumber(m), y>'' and tonumber(y) or nil, oj and tonumber(oj), om>'' and tonumber(om) or nil, oy>'' and tonumber(oy) or nil, tail end return j and tonumber(j), m and tonumber(m), y>'' and tonumber(y) or nil, nil, nil, nil, tail else return nil end end end local function Diffy(d1,m1,y1,d0,m0,y0)--аналог Персона/Дата/Прошло лет return y1-y0 - ( y1*y0<=0 and 1 or 0 ) - ( (m1<m0 or m1==m0 and d1<d0) and 1 or 0 ) end local function Year0(y,t)-- аналог Год0 if y>0 then return table.concat{ '[[', tostring(y), ' год|', t and tostring(y)..'&nbsp;'..t or tostring(y), ']]' } else return table.concat{ '[[', tostring(-y), ' год до н. э.|', t and tostring(-y)..'&nbsp;'..t or tostring(-y), '&nbsp;до&nbsp;н.&nbsp;э.]]' } end end local function FormDate(j,m,y,oj,om,oy,mo)-- ~ Персона/Дата/Logic 4 if j then if not m then return "''формат неверен''" end if y then return string.format( '<span class="nowrap">%s<span style="display:none">(<span class="%s">%04i-%02i-%02i</span>)</span></span>', table.concat( oj and ( om and ( oy and {-- ДД ММММ ГГГГ ([[ДД ММММ]] [[ГГГГ]]) oj,'&nbsp;',monthg[om],'&nbsp;',oy, '</span> <span class="nowrap">([[', j, ' ', monthg[m],']] ',Year0(y),')' } or {-- ДД ММММ ([[ДД ММММ]]) [[ГГГГ]] oj,'&nbsp;',monthg[om],' ([[',j,'&nbsp;',monthg[m],']]) ',Year0(y) } ) or {-- ДД [[ДД ММММ|(ДД) ММММ]] [[ГГГГ]] oj,'&nbsp;[[',j,' ',monthg[m],'|','(',j,')&nbsp;',monthg[m],']] ',Year0(y) } ) or {'[[',j,'&nbsp;',monthg[m],']]&nbsp;',Year0(y)} ),--/table.concat ({['Рождения']='bday',['Смерти']='dday'})[mo] or '', y,m,j )--/string.format else return '<span class="nowrap">' .. table.concat( oj and ( om and {-- ДД ММММ ([[ДД ММММ]]) oj,'&nbsp;',monthg[om],' ([[',j,'&nbsp;',monthg[m],']])</span>' } or {-- ДД [[ДД ММММ|(ДД) ММММ]] oj,'&nbsp;[[',j,' ',monthg[m],'|','(',j,')&nbsp;',monthg[m],']]</span>' } ) or {'[[',j,'&nbsp;',monthg[m],']]</span>'} ) end else return y and string.format( '<span class="nowrap">%s<span style="display:none;">(<span class="bday">%04i</span>)</span></span>', Year0(y,'год'),y) or "''формат неверен''" end end local function GetDate(D)--dd.mm.-?yyyy или -?yyyy-mm-dd в три переменных d,m,y local d,m,y = d:match('^%s*(%d%d?)[/.]([01]?%d)[/.](%-?%d+)') if not d then y,m,d = D:match('^%s*(%-?%d+)[-\\]0*(1?%d)[-\\]0*(%d+)') end return tonumber(d),tonumber(m),tonumber(y) end local function Cmp(a,b)--Сравнивает две даты, результат соответственно -1, 0 или 1 local d1,m1,y1 = GetDate(a) local d2,m2,y2 = GetDate(b) return d1 and d2 and (--nil, если формат не опознан y1==y2 and ( m1==m2 and ( d1==d2 and 0 or d1<d2 and -1 or 1 ) or m1<m2 and -1 or 1 ) or y1<y2 and -1 or 1 ) end local function Yyyymmdd(r)--Переводит русскую дату в YYYY,MM,DD local d, m, y, M = mw.ustring.match(r, "^%s*(%d%d?)%s+([а-яА-Я]+)%s+(%d+)") if not m then return nil end m = mw.ustring.lower(m) --тупо перебор for i = 1, 12 do if m == monthg[i] then M = i break end end if not M then return nil end return tonumber(y), M, tonumber(d) end local p = {} p = { ifdate=function(f)-- Для шаблона "Если дата", имитирует старое поведение -- Аргументы передаются шаблону return f:getParent().args[ mw.ustring.match(frame.args[1],"^[ %d.%-−%()]*$") and 2 or 3 ] end; DecodeDate = DecodeDate; Diffy = Diffy; Year0 = Year0; GetDate = GetDate; Cmp = Cmp; Yyyymmdd = Yyyymmdd; diffy = function(f)-- принимает параметры #invoke в виде двух строк-дат local d1,m1,y1=DecodeDate(f.args[1]); local d0,m0,y0=DecodeDate(f.args[2]) return Diffy(d1,m1,y1,d0,m0,y0) end; monthg=function(f) return monthg[ f.args[1] or f:getParent().args[1] ] end;--realmonth persdate=function(f)-- Для шаблона Персона/Дата;{{#invoke:dates|persdate|nocat={{NAMESPACE}}}} local frame=f:getParent(); local catpref,mo,d,d2={['Рождения']='Родившиеся',['Смерти']='Умершие'}, frame.args[1],frame.args[2],frame.args[3] local cat, j,m,y,oj,om,oy,tail, j2,m2,y2, age = '' if d then j,m,y,oj,om,oy,tail=DecodeDate(d:gsub('−','-')); if not (j or y) then return (frame.args.nocat and d or d..'[[Category:Википедия:Статьи с ручной викификацией дат в карточке]]') end end; if d2 then j2,m2,y2 = DecodeDate(d2:gsub('−','-')); end; return table.concat{ FormDate(j,m,y,oj,om,oy,mo), ( (frame.args['nopersoncat'] or '')~='' or (f.args['nocat'] or '')~='' ) and '' or table.concat{ '[[Category:Персоналии по алфавиту]]', j and string.format('[[Category:%s %i %s]]',catpref[mo],j,monthg[m]) or '', y and string.format('[[Category:%s в %s]]',catpref[mo],y,Year0(y,'году')) or '' },--/table.concat внутр. (function(F)--возраст if not F then return '' end; local n=F(); return n and string.format(" (%i %s)%s", n, mw.getLanguage('ru'):plural(n,'год','года','лет'), n>150 and '[[Category:Википедия:Статьи о персоналиях с большим текущим возрастом]]' or '' ) or '' end)( ({ ['Рождения']=function() local now=os.date('*t'); if (not d2 or d2=='') and j and m and y then return Diffy(now.day,now.month,now.year,j,m,y) end end, ['Смерти']=function() return j and m and y and j2 and m2 and y2 and Diffy(j,m,y,j2,m2,y2); end, })[mo] ),--конец вызова функции возраста tail or '', cat }--/table.concat внеш. end; formdate=function(f) -- Формирует дату по 3--6 параметрам #invoke или шаблона --не использовать с пустыми аргументами if (f.args[1] or '')~='' and (f.args[2] or '')~='' or (f.args[3] or '')~='' then return FormDate(f.args[1],f.args[2],f.args[3],f.args[4],f.args[5],f.args[6],f.args['m']) else local tf=f:getParent(); return FormDate(tf.args[1],tf.args[2],tf.args[3],tf.args[4],tf.args[5],tf.args[6],tf.args['m']) end end; cmp=function(f)--Сравнивает две даты, результат соответственно -1, 0 или 1 return Cmp(f.args[1],f.args[2]) end; G2J=function(f)--перевод григорианских дат в юлианские, возврат DD.MM.YYYY --Не знает про 15 октября 1582 года, не работает до нашей эры и после ???99 года --Если есть второй аргумент, преобразует только ДО этой даты включительно --Если есть третий аргумент, результат форматирует под Персона/Дата local d,m,y=GetDate(f.args[1]) if f.args[2] and Cmp(f.args[1],f.args[2])==1 then return string.format("%i.%i.%i",d,m,y) end local shift=math.floor(y/100)-math.floor(y/400)-2 if d-shift>0 then return f.args[3] and string.format("%i.%i.%i (%i)",d,m,y,d-shift) or string.format("%i.%i.%i",d-shift,m,y) else if m==1 then return f.args[3] and string.format("%i.1.%i (%i.12.%i)",d,y,31+d-shift,y-1) or string.format("%i.12.%i",31+d-shift,y-1) elseif m==3 then return f.args[3] and string.format("%i.3.%i (%i.2)", d,y, (y%4==0 and 29 or 28)+d-shift-(y%100==0 and y%400~=0 and 1 or 0) ) or string.format("%i.2.%i", (y%4==0 and 29 or 28)+d-shift-(y%100==0 and y%400~=0 and 1 or 0) ,y) else return f.args[3] and string.format( "%i.%i.%i (%i.%i)", d,m,y, monthd[m-1]+d-shift,m-1 ) or string.format("%i.%i.%i",monthd[m-1]+d-shift,m-1,y) end end end; -- Переводит русскую дату в YYYY-MM-DD. Возвращает входное значение, если дата уже в этом формате yyyymmdd = function(f) local date, hourmin = f.args[1] if mw.ustring.match(date, "^%s*%d+\-%d+\-%d+") then return date end hourmin = mw.ustring.match(date, "%s+%d+:%d+$") local y, m, d = Yyyymmdd(date) if not y then return '<span class="error">Ошибка: некорректный формат даты.</span>' end return string.format('%4i-%02i-%02i', y, m, d) .. (hourmin or '') end } function table.val_to_str ( v ) if "string" == type( v ) then v = string.gsub( v, "\n", "\\n" ) if string.match( string.gsub(v,"[^'\"]",""), '^"+$' ) then return "'" .. v .. "'" end return '"' .. string.gsub(v,'"', '\\"' ) .. '"' else return "table" == type( v ) and table.tostring( v ) or tostring( v ) end end function table.key_to_str ( k ) if "string" == type( k ) and string.match( k, "^[_%a][_%a%d]*$" ) then return k else return "[" .. table.val_to_str( k ) .. "]" end end function table.tostring( tbl ) local result, done = {}, {} for k, v in ipairs( tbl ) do table.insert( result, table.val_to_str( v ) ) done[ k ] = true end for k, v in pairs( tbl ) do if not done[ k ] then table.insert( result, table.key_to_str( k ) .. "=" .. table.val_to_str( v ) ) end end return "{" .. table.concat( result, "," ) .. "}" end local function parseISO8601Date(str) local pattern = "(%-?%d+)%-(%d+)%-(%d+)T" local Y, M, D = mw.ustring.match( str, pattern ) return tonumber(Y), tonumber(M), tonumber(D) end local function parseISO8601Time(str) local pattern = "T(%d+):(%d+):(%d+)%Z" local H, M, S = mw.ustring.match( str, pattern) return tonumber(H), tonumber(M), tonumber(S) end local function parseISO8601Offset(str) if str:sub(-1)=="Z" then return 0,0 end -- ends with Z, Zulu time -- matches ±hh:mm, ±hhmm or ±hh; else returns nils local pattern = "([-+])(%d%d):?(%d?%d?)$" local sign, oh, om = mw.ustring.match( str, pattern) sign, oh, om = sign or "+", oh or "00", om or "00" return tonumber(sign .. oh), tonumber(sign .. om) end function p.parseISO8601(str) if 'table'==type(str) then if str.args and str.args[1] then str = '' .. str.args[1] else return 'unknown argument type: ' .. type( str ) .. ': ' .. table.tostring( str ) end end local Y,M,D = parseISO8601Date(str) local h,m,s = parseISO8601Time(str) local oh,om = parseISO8601Offset(str) return tonumber(os.time({year=Y, month=M, day=D, hour=(h+oh), min=(m+om), sec=s})) end local g2uBoundary1 = p.parseISO8601('1582-10-15T00:00:00Z') local g2uBoundary2 = p.parseISO8601('1700-03-12T00:00:00Z') local g2uBoundary3 = p.parseISO8601('1800-03-13T00:00:00Z') local g2uBoundary4 = p.parseISO8601('1900-03-14T00:00:00Z') local g2uBoundary5 = p.parseISO8601('1918-01-26T00:00:00Z') -- декрет Ленина -- Передаваемое время обязано быть по Григорианскому календарю (новому стилю) function p.formatWiki( time, infocardClass, categoryNamePrefix ) if 'table'==type( time ) then if time.args and time.args[1] then time = tonumber( time.args[1] ) else return 'unknown argument type: ' .. type( time ) .. ': ' .. table.tostring( time ) end end local t = os.date("*t", time) if time < g2uBoundary1 then -- выводим просто юлианский календарь. Задавать тут григорианский некорректно return p.formatWikiImpl( t, t, infocardClass, categoryNamePrefix ) end -- Специальные даты if t.year == 1700 and t.month == 3 and t.day == 11 then return p.formatWikiImpl( {year=1700, month=2, day=29}, t, infocardClass, categoryNamePrefix) end if t.year == 1800 and t.month == 3 and t.day == 12 then return p.formatWikiImpl( {year=1800, month=2, day=29}, t, infocardClass, categoryNamePrefix ) end if t.year == 1900 and t.month == 3 and t.day == 13 then return p.formatWikiImpl( {year=1900, month=2, day=29}, t, infocardClass, categoryNamePrefix ) end if g2uBoundary1 <= time and time < g2uBoundary2 then return p.formatWikiImpl( os.date("*t", time - 10 * 24 * 60 * 60), t, infocardClass, categoryNamePrefix ) end if g2uBoundary2 <= time and time < g2uBoundary3 then return p.formatWikiImpl( os.date("*t", time - 11 * 24 * 60 * 60), t, infocardClass, categoryNamePrefix ) end if g2uBoundary3 <= time and time < g2uBoundary4 then return p.formatWikiImpl( os.date("*t", time - 12 * 24 * 60 * 60), t, infocardClass, categoryNamePrefix ) end if g2uBoundary4 <= time and time < g2uBoundary5 then return p.formatWikiImpl( os.date("*t", time - 13 * 24 * 60 * 60), t, infocardClass, categoryNamePrefix ) end --только Григорианский календарь return p.formatWikiImpl( t, t, infocardClass, categoryNamePrefix ) end local function ternary ( cond , T , F ) if cond then return T else return F end end local nominativeMonthes = {'январь', 'февраль', 'март', 'апрель', 'май', 'июнь', 'июль', 'август', 'сентябрь', 'октябрь', 'ноябрь', 'декабрь'} local genitivusMonthes = {'января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря'} local function nominativeYear( year, nolinks ) if ( year >= 0 ) then return nolinks and year or '[[' .. year .. ' год|' .. year .. ']]' else return nolinks and ( 0 - year ) .. ' до н. э.' or '[[' .. ( 0 - year ) .. ' год до н. э.|' .. ( 0 - year ) .. ' до н. э.]]' end end local function inYear( year ) if ( year >= 0 ) then return '' .. year .. ' году' else return '' .. ( 0 - year) .. ' году до н. э.' end end function p.formatWikiImpl( t1, t2, infocardClass, categoryNamePrefix, leftBracket, rightBracket, nolinks ) local nd = t2.day; local nm = t2.month; local ny = t2.year; local od = ternary ( t1.day ~= t2.day , t1.day, nil ); local om = ternary ( t1.month ~= t2.month , t1.month, nil ); local oy = ternary ( t1.year ~= t2.year , t1.year, nil ); if leftBracket == nil then leftBracket = '(' end if rightBracket == nil then rightBracket = ')' end local JulianComment = function(s) return tostring(mw.html.create("abbr") :attr("title","по юлианскому календарю") :wikitext(s) :done()) end local template = (nd ~= nil and "1" or "") .. (nm ~= nil and "2" or "") .. (ny ~= nil and "3" or "") .. (od ~= nil and "4" or "") .. (om ~= nil and "5" or "") .. (oy ~= nil and "6" or "") local datePart = '<span class="nowrap">' if (template == "12") then datePart = datePart .. string.format( nolinks and "%d %s" or "[[%d %s]]", nd, genitivusMonthes[nm] ) elseif (template == "23") then datePart = datePart .. string.format( "%s %s", nominativeMonthes[nm], nominativeYear( ny, nolinks ) ) elseif (template == "3") then datePart = datePart .. nominativeYear( ny, nolinks ) elseif (template == "123") then datePart = datePart .. string.format( nolinks and "%d %s %s" or "[[%d %s]] %s", nd, genitivusMonthes[nm], nominativeYear( ny, nolinks ) ) elseif (template == "124") then if nolinks then datePart = datePart .. JulianComment(string.format( "%d", od ) ).. string.format( " " .. leftBracket .. "%d" .. rightBracket .. " %s", nd, genitivusMonthes[nm] ) else datePart = datePart .. JulianComment(string.format( "%d", od ) ).. string.format( " [[%d %s|" .. leftBracket .. "%d" .. rightBracket .. " %s]]", nd, genitivusMonthes[nm], nd, genitivusMonthes[nm] ) end elseif (template == "1234") then if nolinks then datePart = datePart .. JulianComment(string.format( "%d", od ) ).. string.format( " |" .. leftBracket .. "%d" .. rightBracket .. " %s %s", nd, genitivusMonthes[nm], nominativeYear( ny, nolinks ) ) else datePart = datePart .. JulianComment(string.format( "%d", od ) ).. string.format( " [[%d %s|" .. leftBracket .. "%d" .. rightBracket .. " %s]] %s", nd, genitivusMonthes[nm], nd, genitivusMonthes[nm], nominativeYear( ny, nolinks ) ) end elseif (template == "1245") then datePart = datePart .. JulianComment(string.format( "%d %s", od, genitivusMonthes[om] ) ).. string.format(" " .. leftBracket .. (nolinks and "%d %s" or "[[%d %s]]") .. rightBracket .. "", nd, genitivusMonthes[nm] ) elseif (template == "12345") then datePart = datePart .. JulianComment(string.format( "%d %s", od, genitivusMonthes[om] ) ).. string.format(" " .. leftBracket .. (nolinks and "%d %s" or "[[%d %s]]") .. rightBracket .. " %s", nd, genitivusMonthes[nm], nominativeYear( ny, nolinks ) ) elseif (template == "123456") then datePart = datePart .. JulianComment(string.format( "%d %s %d", od, genitivusMonthes[om], oy )) .. '</span> <span class="nowrap">' .. string.format(" " .. leftBracket .. (nolinks and "%d %s %s" or "[[%d %s]] %s") .. rightBracket , nd, genitivusMonthes[nm], nominativeYear( ny, nolinks ) ) else datePart = datePart .. 'формат неверен' end datePart = datePart .. '</span>' local infocardTemplate = (nd ~= nil and "1" or "") .. (nm ~= nil and "2" or "") .. (ny ~= nil and "3" or "") if infocardClass then if (infocardTemplate == "123") then datePart = datePart .. string.format('<span style="display:none">(<span class="%s">%04d-%02d-%02d</span>)</span>', infocardClass , ny , nm , nd ) elseif (infocardTemplate == "23") then datePart = datePart .. string.format('<span style="display:none">(<span class="%s">%04d-%02d</span>)</span>', infocardClass , ny , nm ) elseif (infocardTemplate == "3") then datePart = datePart .. string.format('<span style="display:none;">(<span class="%s">%04d</span>)</span>', infocardClass , ny ) end end if categoryNamePrefix then if ( nd ~= nil and nm ~= nil) then datePart = datePart .. '[[Category:' .. categoryNamePrefix .. ' ' .. nd .. ' ' .. genitivusMonthes[nm] .. ']]' end if ( ny ~= nil) then datePart = datePart .. '[[Category:' .. categoryNamePrefix .. ' в ' .. inYear( ny ) .. ']]' end end return datePart end return p 902bb6a9ef5ce12ad4cfa19f3d2c964d7e092df7 Шаблон:Lang-en 10 62 122 121 2025-01-25T21:00:28Z Vallenland 2 1 версия импортирована wikitext text/x-wiki <nowiki />[[английский язык|англ.]]&nbsp;{{lang-en2|{{{1}}}}}<noinclude> {{doc|Lang/doc}} </noinclude> 6fcc1d4dc63f133033671bf27e48a6e701e126cb Шаблон:Lang-en2 10 63 124 123 2025-01-25T21:00:28Z Vallenland 2 1 версия импортирована wikitext text/x-wiki {{langi|en|{{{1}}}}}<noinclude> {{doc|Lang/doc}} </noinclude> 0471cf4d45a13ece481915d5c3e55db65d6aca04 Модуль:Color contrast 828 64 126 125 2025-01-25T21:00:28Z Vallenland 2 1 версия импортирована Scribunto text/plain -- -- This module implements -- {{Color contrast ratio}} -- {{Greater color contrast ratio}} -- {{ColorToLum}} -- {{RGBColorToLum}} -- local p = {} local HTMLcolor = mw.loadData( 'Module:Color contrast/colors' ) local function sRGB ( v ) if (v <= 0.03928) then v = v / 12.92 else v = math.pow((v+0.055)/1.055, 2.4) end return v end local function rgbdec2lum( R, G, B ) if ( 0 <= R and R < 256 and 0 <= G and G < 256 and 0 <= B and B < 256 ) then return 0.2126 * sRGB(R/255) + 0.7152 * sRGB(G/255) + 0.0722 * sRGB(B/255) else return '' end end local function hsl2lum( h, s, l ) if ( 0 <= h and h < 360 and 0 <= s and s <= 1 and 0 <= l and l <= 1 ) then local c = (1 - math.abs(2*l - 1))*s local x = c*(1 - math.abs( math.fmod(h/60, 2) - 1) ) local m = l - c/2 local r, g, b = m, m, m if( 0 <= h and h < 60 ) then r = r + c g = g + x elseif( 60 <= h and h < 120 ) then r = r + x g = g + c elseif( 120 <= h and h < 180 ) then g = g + c b = b + x elseif( 180 <= h and h < 240 ) then g = g + x b = b + c elseif( 240 <= h and h < 300 ) then r = r + x b = b + c elseif( 300 <= h and h < 360 ) then r = r + c b = b + x end return rgbdec2lum(255*r, 255*g, 255*b) else return '' end end local function color2lum( c ) if (c == nil) then return '' end -- whitespace c = c:match( '^%s*(.-)[%s;]*$' ) -- lowercase c = c:lower() -- first try to look it up local L = HTMLcolor[c] if (L ~= nil) then return L end -- convert from hsl if mw.ustring.match(c,'^hsl%([%s]*[0-9][0-9%.]*[%s]*,[%s]*[0-9][0-9%.]*%%[%s]*,[%s]*[0-9][0-9%.]*%%[%s]*%)$') then local h, s, l = mw.ustring.match(c,'^hsl%([%s]*([0-9][0-9%.]*)[%s]*,[%s]*([0-9][0-9%.]*)%%[%s]*,[%s]*([0-9][0-9%.]*)%%[%s]*%)$') return hsl2lum(tonumber(h), tonumber(s)/100, tonumber(l)/100) end -- convert from rgb if mw.ustring.match(c,'^rgb%([%s]*[0-9][0-9]*[%s]*,[%s]*[0-9][0-9]*[%s]*,[%s]*[0-9][0-9]*[%s]*%)$') then local R, G, B = mw.ustring.match(c,'^rgb%([%s]*([0-9][0-9]*)[%s]*,[%s]*([0-9][0-9]*)[%s]*,[%s]*([0-9][0-9]*)[%s]*%)$') return rgbdec2lum(tonumber(R), tonumber(G), tonumber(B)) end -- convert from rgb percent if mw.ustring.match(c,'^rgb%([%s]*[0-9][0-9%.]*%%[%s]*,[%s]*[0-9][0-9%.]*%%[%s]*,[%s]*[0-9][0-9%.]*%%[%s]*%)$') then local R, G, B = mw.ustring.match(c,'^rgb%([%s]*([0-9][0-9%.]*)%%[%s]*,[%s]*([0-9][0-9%.]*)%%[%s]*,[%s]*([0-9][0-9%.]*)%%[%s]*%)$') return rgbdec2lum(255*tonumber(R)/100, 255*tonumber(G)/100, 255*tonumber(B)/100) end -- remove leading # (if there is one) and whitespace c = mw.ustring.match(c, '^[%s#]*([a-f0-9]*)[%s]*$') -- split into rgb local cs = mw.text.split(c or '', '') if( #cs == 6 ) then local R = 16*tonumber('0x' .. cs[1]) + tonumber('0x' .. cs[2]) local G = 16*tonumber('0x' .. cs[3]) + tonumber('0x' .. cs[4]) local B = 16*tonumber('0x' .. cs[5]) + tonumber('0x' .. cs[6]) return rgbdec2lum(R, G, B) elseif ( #cs == 3 ) then local R = 16*tonumber('0x' .. cs[1]) + tonumber('0x' .. cs[1]) local G = 16*tonumber('0x' .. cs[2]) + tonumber('0x' .. cs[2]) local B = 16*tonumber('0x' .. cs[3]) + tonumber('0x' .. cs[3]) return rgbdec2lum(R, G, B) end -- failure, return blank return '' end function p._greatercontrast(args) local bias = tonumber(args['bias'] or '0') or 0 local v1 = color2lum(args[1] or '') local c2 = args[2] or '#FFFFFF' local v2 = color2lum(c2) local c3 = args[3] or '#000000' local v3 = color2lum(c3) local ratio1 = 0; local ratio2 = 0; if (type(v1) == 'number' and type(v2) == 'number') then ratio1 = (v2 + 0.05)/(v1 + 0.05) ratio1 = (ratio1 < 1) and 1/ratio1 or ratio1 end if (type(v1) == 'number' and type(v3) == 'number') then ratio2 = (v3 + 0.05)/(v1 + 0.05) ratio2 = (ratio2 < 1) and 1/ratio2 or ratio2 end return (ratio1 + bias > ratio2) and c2 or c3 end function p._ratio(args) local v1 = color2lum(mw.text.unstripNoWiki(args[1] or '')) local v2 = color2lum(mw.text.unstripNoWiki(args[2] or '')) if (type(v1) == 'number' and type(v2) == 'number') then -- v1 should be the brighter of the two. if v2 > v1 then v1, v2 = v2, v1 end return (v1 + 0.05)/(v2 + 0.05) else return args['error'] or '?' end end function p._styleratio(args) local style = (args[1] or ''):lower() local bg, fg = 'white', '#202122' local lum_bg, lum_fg = 1, 0.016 if args[2] then local lum = color2lum(args[2]) if lum ~= '' then bg, lum_bg = args[2], lum end end if args[3] then local lum = color2lum(args[3]) if lum ~= '' then fg, lum_fg = args[3], lum end end local slist = mw.text.split(style or '', ';') for k = 1, #slist do local s = slist[k] local k, v = s:match( '^[%s]*([^:]-):([^:]-)[%s;]*$' ) k = k or '' v = v or '' if (k:match('^[%s]*(background)[%s]*$') or k:match('^[%s]*(background%-color)[%s]*$')) then local lum = color2lum(v) if( lum ~= '' ) then bg, lum_bg = v, lum end elseif (k:match('^[%s]*(color)[%s]*$')) then local lum = color2lum(v) if( lum ~= '' ) then bg, lum_fg = v, lum end end end if lum_bg > lum_fg then return (lum_bg + 0.05)/(lum_fg + 0.05) else return (lum_fg + 0.05)/(lum_bg + 0.05) end end function p.lum(frame) return color2lum(frame.args[1] or frame:getParent().args[1]) end function p.ratio(frame) local args = frame.args[1] and frame.args or frame:getParent().args return p._ratio(args) end function p.styleratio(frame) local args = frame.args[1] and frame.args or frame:getParent().args return p._styleratio(args) end function p.greatercontrast(frame) local args = frame.args[1] and frame.args or frame:getParent().args return p._greatercontrast(args) end return p cce580326bee8eaf3c81df6c76c04a9a2909dfa2 Модуль:Color contrast/colors 828 65 128 127 2025-01-25T21:00:29Z Vallenland 2 1 версия импортирована Scribunto text/plain return { aliceblue = 0.92880068253475, antiquewhite = 0.84646951707754, aqua = 0.7874, aquamarine = 0.8078549208338, azure = 0.97265264954166, beige = 0.8988459998705, bisque = 0.80732327372979, black = 0, blanchedalmond = 0.85084439608156, blue = 0.0722, blueviolet = 0.12622014321946, brown = 0.098224287876511, burlywood = 0.51559844533893, cadetblue = 0.29424681085422, chartreuse = 0.76032025902623, chocolate = 0.23898526114557, coral = 0.37017930872924, cornflowerblue = 0.30318641994179, cornsilk = 0.93562110372965, crimson = 0.16042199953026, cyan = 0.7874, darkblue = 0.018640801980939, darkcyan = 0.20329317839046, darkgoldenrod = 0.27264703559993, darkgray = 0.39675523072563, darkgreen = 0.091143429047575, darkgrey = 0.39675523072563, darkkhaki = 0.45747326349994, darkmagenta = 0.07353047651207, darkolivegreen = 0.12651920884889, darkorange = 0.40016167026524, darkorchid = 0.13413142174857, darkred = 0.054889674531132, darksalmon = 0.40541471563381, darkseagreen = 0.43789249325969, darkslateblue = 0.065792846227988, darkslategray = 0.067608151928044, darkslategrey = 0.067608151928044, darkturquoise = 0.4874606277449, darkviolet = 0.10999048339343, deeppink = 0.23866895828276, deepskyblue = 0.44481603395575, dimgray = 0.14126329114027, dimgrey = 0.14126329114027, dodgerblue = 0.27442536991456, firebrick = 0.10724525535015, floralwhite = 0.95922484825004, forestgreen = 0.18920812076002, fuchsia = 0.2848, gainsboro = 0.71569350050648, ghostwhite = 0.94311261886323, gold = 0.69860877428159, goldenrod = 0.41919977809569, gray = 0.2158605001139, green = 0.15438342968146, greenyellow = 0.80609472611453, grey = 0.2158605001139, honeydew = 0.96336535554782, hotpink = 0.34658438169715, indianred = 0.21406134963884, indigo = 0.03107561486337, ivory = 0.99071270600615, khaki = 0.77012343394121, lavender = 0.80318750514521, lavenderblush = 0.90172748631046, lawngreen = 0.73905893124963, lemonchiffon = 0.94038992245622, lightblue = 0.63709141280807, lightcoral = 0.35522120733135, lightcyan = 0.94587293494829, lightgoldenrodyellow = 0.93348351018297, lightgray = 0.65140563741982, lightgreen = 0.69091979956865, lightgrey = 0.65140563741982, lightpink = 0.58566152734898, lightsalmon = 0.4780675225206, lightseagreen = 0.35050145117042, lightskyblue = 0.56195637618331, lightslategray = 0.23830165007287, lightslategrey = 0.23830165007287, lightsteelblue = 0.53983888284666, lightyellow = 0.98161818392882, lime = 0.7152, limegreen = 0.44571042246098, linen = 0.88357340984379, magenta = 0.2848, maroon = 0.045891942324215, mediumaquamarine = 0.49389703310801, mediumblue = 0.044077780212328, mediumorchid = 0.21639251153773, mediumpurple = 0.22905858091648, mediumseagreen = 0.34393112338131, mediumslateblue = 0.20284629471622, mediumspringgreen = 0.70704308194184, mediumturquoise = 0.5133827926448, mediumvioletred = 0.14371899849357, midnightblue = 0.02071786635086, mintcream = 0.97834604947588, mistyrose = 0.82183047859185, moccasin = 0.80083000991567, navajowhite = 0.76519682342785, navy = 0.015585128108224, oldlace = 0.91900633405549, olive = 0.20027537200568, olivedrab = 0.22593150951929, orange = 0.4817026703631, orangered = 0.25516243753416, orchid = 0.31348806761439, palegoldenrod = 0.78792647887614, palegreen = 0.77936759006353, paleturquoise = 0.76436077921714, palevioletred = 0.28754994117889, papayawhip = 0.87797100199835, peachpuff = 0.74905589878251, peru = 0.30113074877936, pink = 0.63271070702466, plum = 0.45734221587969, powderblue = 0.68254586500605, purple = 0.061477070432439, rebeccapurple = 0.07492341159447, red = 0.2126, rosybrown = 0.32319457649407, royalblue = 0.16663210743188, saddlebrown = 0.097922285020521, salmon = 0.36977241527596, sandybrown = 0.46628543696283, seagreen = 0.19734199706275, seashell = 0.92737862206922, sienna = 0.13697631337098, silver = 0.52711512570581, skyblue = 0.55291668518184, slateblue = 0.14784278062136, slategray = 0.20896704076536, slategrey = 0.20896704076536, snow = 0.96533341834849, springgreen = 0.73052306068529, steelblue = 0.20562642207625, tan = 0.48237604163921, teal = 0.16996855778968, thistle = 0.56818401093733, tomato = 0.30638612719415, turquoise = 0.5895536427578, violet = 0.40315452986676, wheat = 0.74909702820482, white = 1, whitesmoke = 0.91309865179342, yellow = 0.9278, yellowgreen = 0.50762957208707, } 6ae47fdb24de4eed5ec26d203faf5341a388987b Шаблон:Yesno-yes 10 66 130 129 2025-01-25T21:00:29Z Vallenland 2 1 версия импортирована wikitext text/x-wiki {{safesubst:<noinclude />yesno|{{{1}}}|yes={{{yes|yes}}}|no={{{no|no}}}|blank={{{blank|yes}}}|¬={{{¬|yes}}}|def={{{def|yes}}}}}<noinclude> {{doc}} </noinclude> 3792ff694708f98102e3a6d556abe73bedc29069 Шаблон:No-doc 10 67 132 131 2025-01-25T21:00:29Z Vallenland 2 1 версия импортирована wikitext text/x-wiki {{#ifeq: {{SUBPAGENAME}} | doc || {{#if: {{#if: {{yesno|{{{nocat|}}}}} | x }}{{#switch: {{NAMESPACE}} | {{ns:10}} | {{ns:828}} = | x }} || {{{1|}}} }} }}<noinclude>{{doc}}</noinclude> da013ca5b5f97f94bee392ff3a4488046f2ceac7 Модуль:Wikidata/Medals 828 68 134 133 2025-01-25T21:00:30Z Vallenland 2 1 версия импортирована Scribunto text/plain local WDS = require( 'Module:WikidataSelectors' ) local moduleDate = require( 'Module:Wikidata/date' ) local awardsOrder = mw.ext.data.get( "Wikidata/awards order.tab" ) local p = {} local config = { --Hide award with key QID if there is a reward with value QID absorption = { Q16675272 = 'Q654471', Q16481808 = 'Q8706404', Q1948730 = 'Q178473', Q1980962 = 'Q208167', Q2032399 = 'Q2046996', Q102183407 = 'Q103819965', Q1262166 = 'Q80589', Q749849 = 'Q1358055', Q4287121 = 'Q4137462', } } --Get string with dates from qualifiers table local function datesFromQualifier( context, options, qualifierId ) local dates = {} local qualifiers = options.qualifiers[ qualifierId ] if qualifiers then for _, qualifier in pairs( qualifiers ) do if qualifier.datavalue then local dateValue = moduleDate.formatDate( context, options, qualifier.datavalue.value ) if dateValue then table.insert( dates, dateValue ) end end end end return table.concat( dates, ', ' ) end --Property function for [[d:Property:P166]] function p.formatProperty( context, options ) if ( not context ) then error( 'context not specified' ); end; if ( not options ) then error( 'options not specified' ); end; if ( not options.entityId ) then error( 'options.entityId missing' ); end; local claims; if options.property then -- TODO: Почему тут может не быть property? claims = context.selectClaims( options, options.property ); end if claims == nil then return '' --TODO error? end -- Обход всех заявлений утверждения и с накоплением оформленых -- предпочтительных заявлений в таблице. local formattedData = {} for i, claim in ipairs( claims ) do if ( claim.mainsnak and claim.mainsnak and claim.mainsnak.datavalue and claim.mainsnak.datavalue.type == 'wikibase-entityid' ) then local valueId = claim.mainsnak.datavalue.value.id local formattedStatement = context.formatStatement( options, claim ) -- здесь может вернуться либо оформленный текст заявления, либо строка ошибки, либо nil if ( formattedStatement and formattedStatement ~= '' ) then formattedStatement = '<span class="wikidata-claim" data-wikidata-property-id="' .. string.upper( options.property ) .. '" data-wikidata-claim-id="' .. claim.id .. '">' .. formattedStatement .. '</span>' table.insert( formattedData, { id = valueId, html = formattedStatement, } ) end end end -- Удаление дублей (медаль + звание -> звание) for i, awardData in ipairs( formattedData ) do local isAbsorptionFound = false if config.absorption[ awardData.id ] then local absorptionAwardId = config.absorption[ awardData.id ] for _, absorptionAwardData in ipairs( formattedData ) do if absorptionAwardData.id == absorptionAwardId then isAbsorptionFound = true break end end end if isAbsorptionFound then table.remove( formattedData, i ) end end -- Сортировка медалей по старшинству local orderedData = {} local lastValue; if ( type (awardsOrder) == 'table' ) then -- Если не отсохла stuctured data for i, awardFields in ipairs( awardsOrder.data ) do local awardOrder = awardFields[ 1 ] if awardOrder == '-' then -- separator if lastValue ~= '-' then table.insert( orderedData, '<br>' ) lastHeight = nil end else for k, awardData in ipairs( formattedData ) do if awardOrder == awardData.id and not awardData.used then table.insert( orderedData, awardData.html ) formattedData[ k ].used = true end end end end end for i, awardData in ipairs( formattedData ) do if not awardData.used then table.insert( orderedData, awardData.html ) end end local lastHeight for i, awardHtml in ipairs( orderedData ) do local height = mw.ustring.match( awardHtml, 'x%d+px' ) if height and lastHeight and height ~= lastHeight then table.insert( orderedData, i, '<br>' ) end lastHeight = height end -- создание текстовой строки со списком оформленых заявлений из таблицы local out = mw.text.listToText( orderedData, options.separator, options.conjunction ) if out ~= '' then if options.before then out = options.before .. out end if options.after then out = out .. options.after end end return out end local function getImageFromProperty( entityId, propertyId ) local imageClaims = WDS.load( entityId, propertyId ) if imageClaims and #imageClaims > 0 then for _, claim in ipairs( imageClaims ) do if claim.type == 'statement' and claim.mainsnak.snaktype == 'value' then return claim.mainsnak.datavalue.value end end end return nil end -- Получение изображения (планки или иконки) и его размера function p.getImageFromEntity( entityId, actualDate ) if type( entityId ) ~= "string" then entityId = entityId.id end local image = nil local size = 'x17px' local border = false -- получение изображения планки из элемента image = getImageFromProperty( entityId, 'P2425' ) if image then border = true end -- получение иконки из элемента if not image then image = getImageFromProperty( entityId, 'P2910' ) if image then size = '40x40px' end end return image, size, border end --Value function for [[d:Property:P166]] function p.formatValue( context, options, statement ) local entityId = statement.id if not entityId then return statement end local label = mw.wikibase.getLabel( entityId ) local image, size, border = p.getImageFromEntity( entityId ) local recipientCategory = '' if not options.nocat and options.nocat ~= '' then recipientCategory = context.extractCategory( { category = 'P7084[P4224:Q24571879]' }, entityId ) if recipientCategory == '' then recipientCategory = context.extractCategory( { category = 'P2517' }, entityId ) end end local dates = '' if options.qualifiers then local startDates = {} dates = datesFromQualifier( context, options, 'P580' ) if dates ~= '' then local endDates = datesFromQualifier( context, options, 'P582' ) if endDates and endDates ~= '' then dates = dates .. ' — ' .. endDates end else dates = datesFromQualifier( context, options, 'P585' ) end if options.qualifiers.P27 then mw.log('>>>>>>>>>>>>>') for _, claim in ipairs( options.qualifiers.P27 ) do if claim and claim.datavalue and claim.datavalue.value and claim.datavalue.value.id then local categoryOptions = { category = 'P7084[P27:' .. claim.datavalue.value.id .. ']' } recipientCategory = recipientCategory .. context.extractCategory( categoryOptions, entityId ) end end end end -- получение ссылки по идентификатору и вывод планки if image then local link = mw.wikibase.getSitelink( entityId ) local out = '[[File:' .. image if border == true then out = out .. '|border' end out = out .. '|' .. size .. '|link=' -- получение ссылки из родительского элемента -- для степеней обычно только одна общая статья if not link then local partOfClaims = WDS.load( entityId, 'P361' ) -- часть от if not partOfClaims or #partOfClaims == 0 then partOfClaims = WDS.load( entityId, 'P279' ) -- подкласс от end if partOfClaims and #partOfClaims > 0 then for _, claim in ipairs( partOfClaims ) do if claim.type == 'statement' and claim.mainsnak.snaktype == 'value' then link = mw.wikibase.getSitelink( claim.mainsnak.datavalue.value.id ) if link then break end end end end end if link then out = out .. link else out = out .. 'd:' .. entityId end if label then out = out .. '|' .. label end out = out .. ']]' out = out .. recipientCategory return out end local out = context.formatValueDefault( context, options, statement ) if out and out ~= '' then if dates ~= '' then out = out .. ' (' .. dates .. ')' end return '<span style="display:inline-block; text-align:left>' .. out .. recipientCategory .. '</span>' end return '' end --Table for documentation function p.renderDoc() local out = {} for i, awardFields in ipairs( awardsOrder.data ) do local awardId = awardFields[ 1 ] local link = '[[d:' .. awardId .. '|' .. awardId .. ']]' if i == 351 then -- limits table.insert( out, '| … || … || … || … || …' ) elseif i > 351 and i < #awardsOrder.data then -- do nothing elseif awardId == '-' then -- separator table.insert( out, '|' .. i .. '|| colspan="3" | ----' ) else local image, size, border = p.getImageFromEntity( awardId ) if image then image = '[[File:' .. image if border == true then image = image .. '|border' end image = image .. '|' .. size .. ']]' else image = '' end local label = mw.wikibase.getLabel( awardId ) or '' local article = mw.wikibase.getSitelink( awardId ) if article then if label == '' then label = article end label = '[[' .. article .. '|' .. label .. ']]' end local countryStatements = mw.wikibase.getBestStatements( awardId, 'P17' ) local countries = {} if countryStatements then for _, statement in ipairs( countryStatements ) do if statement.mainsnak.datavalue and statement.mainsnak.datavalue.type == 'wikibase-entityid' then local countryId = statement.mainsnak.datavalue.value.id table.insert( countries, mw.wikibase.getLabel( countryId ) ) end end end table.insert( out, '|' .. i .. '||' .. link .. '||' .. image .. '||' .. label .. '||' .. table.concat( countries, ', ' ) ) end end return '{| class="wikitable"\n' .. '! # !! Элемент !! Планка !! Название !! Государство\n|-\n' .. table.concat( out, '\n|-\n' ) .. '\n|}' end return p 4de64e0e2181e8a4487f3e18da893fca9f92660d Модуль:Separated entries 828 69 136 135 2025-01-25T21:00:30Z Vallenland 2 1 версия импортирована Scribunto text/plain -- This module takes positional parameters as input and concatenates them with -- an optional separator. The final separator (the "conjunction") can be -- specified independently, enabling natural-language lists like -- "foo, bar, baz and qux". local compressSparseArray = require('Module:TableTools').compressSparseArray local p = {} function p._main(args) local separator = args.separator -- Decode (convert to Unicode) HTML escape sequences, such as "&#32;" for space. and mw.text.decode(args.separator) or '' local conjunction = args.conjunction and mw.text.decode(args.conjunction) or separator -- Discard named parameters. local values = compressSparseArray(args) return mw.text.listToText(values, separator, conjunction) end local function makeInvokeFunction(separator, conjunction) return function (frame) local args = require('Module:Arguments').getArgs(frame) args.separator = separator or args.separator args.conjunction = conjunction or args.conjunction return p._main(args) end end p.main = makeInvokeFunction() p.br = makeInvokeFunction('<br />') p.newline = makeInvokeFunction('\n') p.comma = makeInvokeFunction(mw.message.new('comma-separator'):plain()) return p 33a68f0a46d62c42b6523a548f0f881e82ecfe58 Шаблон:Флагификация/Германия 10 70 138 137 2025-01-25T21:00:30Z Vallenland 2 1 версия импортирована wikitext text/x-wiki {{ {{{1<noinclude>|флагификация/флаг</noinclude>}}} | alias = Германия | flag alias = Flag of Germany.svg | flag alias-империя = Flag of the German Empire.svg | flag alias-1871 = Flag of the German Empire.svg | flag alias-1919 = Flag of Germany (2-3).svg | flag alias-1933-1 = National flag of Germany 1933-1935.svg | flag alias-1933 = Flag of German Reich (1935–1945).svg | flag alias-1946 = Flag of Germany (1946-1949).svg | flag alias-Берлин = Flag of Berlin.svg | flag alias-ГДР = Flag of East Germany.svg | flag alias-1938 = War Ensign of Germany 1938-1945.svg | flag alias-ВМФ = Naval Ensign of Germany.svg | flag alias-1892 = Kaiserliche Kriegsflagge (1892).png | flag alias-1921 = War Ensign of Germany (1921–1933).svg | var1 = империя | var2 = 1871 | var3 = 1919 | var4 = 1933-1 | var5 = 1933 | var6 = 1946 | var7 = Берлин | var8 = ГДР | var9 = 1938 | var10 = ВМФ | var11 = 1892 | var12 = 1921 | variant = {{{variant|}}} | размер = {{{размер|}}} }} efa3b6861970635c792254f5da10e4efbc3ded5d Шаблон:Флагификация/Великобритания 10 71 140 139 2025-01-25T21:00:31Z Vallenland 2 1 версия импортирована wikitext text/x-wiki {{ {{{1<noinclude>|флагификация/флаг</noinclude>}}} | alias = Великобритания | flag alias = Flag of the United Kingdom.svg | flag alias-1707 = Union flag 1606 (Kings Colors).svg | flag alias-1658 = Flag of the Commonwealth (1658-1660).svg | flag alias-1651 = Flag of The Commonwealth.svg | flag alias-1649 = Flag of the Commonwealth (1649-1651).svg | flag alias-1606 = Union flag 1606 (Kings Colors).svg | flag alias-ВМС = Naval Ensign of the United Kingdom.svg | flag alias-торговый = Civil Ensign of the United Kingdom.svg | flag alias-ВВС = Ensign of the Royal Air Force.svg | flag alias-дипломатический = Government Ensign of the United Kingdom.svg | flag alias-армия = Flag of the British Army.svg | variant = {{{variant|}}} <noinclude> | var1 = 1707 | var2 = 1658 | var3 = 1651 | var4 = 1649 | var5 = 1606 | var6 = ВМС | var7 = торговый | var8 = ВВС | var9 = дипломатический | var10 = армия </noinclude> | размер = {{{размер|}}} }} 4bf44640a433c2a79fdf1d0e148897cad36f0f4d Шаблон:Tl 10 72 142 141 2025-01-25T21:00:31Z Vallenland 2 1 версия импортирована wikitext text/x-wiki {{{{{|safesubst:}}}#invoke: Template call code | withoutParams }}<noinclude>{{doc}}</noinclude> 61fe4d068895a5e7e5802767f5d7df71a7561c57 Шаблон:Str sub 10 73 144 143 2025-01-25T21:00:31Z Vallenland 2 1 версия импортирована wikitext text/x-wiki <includeonly>{{{{{|safesubst:}}}#invoke:String|sublength|s={{{1}}}|i={{{2|0}}}|len={{{3|0}}}}}</includeonly><noinclude> {{doc}} </noinclude> 3043790f8803e868cf6097b475fd58ba742887fe Шаблон:Без начала 10 74 146 145 2025-01-25T21:00:31Z Vallenland 2 1 версия импортирована wikitext text/x-wiki {{<includeonly>safesubst:</includeonly>#ifeq:{{<includeonly>safesubst:</includeonly>Str_left|{{{1}}}|{{<includeonly>safesubst:</includeonly>#expr:{{<includeonly>safesubst:</includeonly>str len|{{{2}}}*}}-1}}}}*|{{{2}}}*|{{<includeonly>safesubst:</includeonly>Str_right|{{{1}}}|{{<includeonly>safesubst:</includeonly>#expr:{{<includeonly>safesubst:</includeonly>str len|{{{2}}}*}}-1}}}}|{{{1}}}}}<noinclude>{{doc}}</noinclude> 9fbca6f1fc236cb17fe77d76891e3f9c2afa2117 Шаблон:Str len 10 75 148 147 2025-01-25T21:00:31Z Vallenland 2 1 версия импортирована wikitext text/x-wiki {{{{{|safesubst:}}}#invoke:String|len|s={{{1|}}}}}<noinclude> {{doc}} <!-- Add categories and interwikis to the /doc subpage, not here! --> </noinclude> 95f10258d5214440d2706952656564f216c2e4cc Шаблон:Str rightc 10 76 150 149 2025-01-25T21:00:31Z Vallenland 2 1 версия импортирована wikitext text/x-wiki {{<includeonly>safesubst:</includeonly>Str sub|{{{1}}}|{{<includeonly>safesubst:</includeonly>#expr:{{<includeonly>safesubst:</includeonly>Str len|{{{1}}}}}-{{{2}}}}}|{{{2}}}}}<noinclude>{{doc}}</noinclude> 0401d500dcc2224d44867ba0ea1f6c0fbeb758a0 Модуль:Wikidata/url 828 77 152 151 2025-01-25T21:00:32Z Vallenland 2 1 версия импортирована Scribunto text/plain local p = {} local function formatLangRefs( options ) local langRefs = {} if options.qualifiers and options.qualifiers.P407 then for _, qualifier in ipairs( options.qualifiers.P407 ) do if ( qualifier and qualifier.datavalue and qualifier.datavalue.type == 'wikibase-entityid' ) then local qualifierId = qualifier.datavalue.value.id local wbStatus, langRefCodeClaims = pcall( mw.wikibase.getBestStatements, qualifierId, 'P218' ) if wbStatus and langRefCodeClaims then for _, claim in ipairs( langRefCodeClaims ) do if ( claim.mainsnak and claim.mainsnak.datavalue and claim.mainsnak.datavalue.type == 'string' ) then local langRefCode = claim.mainsnak.datavalue.value table.insert( langRefs, options.frame:expandTemplate{ title = 'ref-' .. langRefCode } ) end end end end end end return table.concat( langRefs, '&#8203;' ) end function p.formatUrlValue( context, options, value ) local moduleUrl = require( 'Module:URL' ) local langRefs = formatLangRefs( options ) if not options.length or options.length == '' then options.length = math.max( 18, 25 - #langRefs ) end return moduleUrl.formatUrlSingle( context, options, value ) .. langRefs end return p 4a9959f45666b35899729e561a73e0535c16e15e Шаблон:Цвет/Вокалист.css 10 78 154 153 2025-01-25T21:00:32Z Vallenland 2 1 версия импортирована text text/plain .infobox-above, .infobox-header, .infobox-below { background: #f0e68c; } @media screen { html.skin-theme-clientpref-night .infobox-above, html.skin-theme-clientpref-night .infobox-header, html.skin-theme-clientpref-night .infobox-below { background: #302a00; } } @media screen and (prefers-color-scheme: dark) { html.skin-theme-clientpref-os .infobox-above, html.skin-theme-clientpref-os .infobox-header, html.skin-theme-clientpref-os .infobox-below { background: #302a00; } } /* [[Категория:Шаблоны:Подстраницы CSS]] [[Категория:Шаблоны:Цвета по темам:Музыка|Вокалист.css]] */ 2e2ee1ff27b701bb561598af95c43d81a92319bc Модуль:Hash 828 79 156 155 2025-01-25T21:00:32Z Vallenland 2 1 версия импортирована Scribunto text/plain local getArgs = require('Module:Arguments').getArgs local p = {} local function inTable(table, value) for k, v in pairs(table) do if v == value then return true end end return false end function p.list(frame) return table.concat(mw.hash.listAlgorithms(), '; ') end function p.main(frame) local args = getArgs(frame, { frameOnly = true }) local algorithm if not args[1] then return '<span class="error">Не указана строка для хеширования.</span>' end if args[2] then if not inTable(mw.hash.listAlgorithms(), args[2]) then return '<span class="error">Алгоритм хеширования ' .. args[2] .. ' не поддерживается, или вы неточно указали его имя. Используйте функцию <kbd>mw.hash.listAlgorithms()</kbd> для получения списка доступных алгоритмов.</span>' end algorithm = args[2] else -- Алгоритм выбран из соображений быстродействия (см. [[:en:Fowler–Noll–Vo hash function]]), -- 64-битная функция используется для уменьшения вероятности коллизий до пренебрежимо малой -- величины. Возможно, есть лучшая опция — проверяйте. algorithm = 'fnv164' end return mw.hash.hashValue(algorithm, args[1]) end return p 5d18513e574435f191164695449a620b031f93ec Шаблон:Lang-de 10 80 158 157 2025-01-25T21:00:33Z Vallenland 2 1 версия импортирована wikitext text/x-wiki [[Немецкий язык|нем.]]&nbsp;{{langi|de|{{{1}}}}}<noinclude>{{doc|Lang/doc}}</noinclude> 646eff5eb102894e6474a9c639b707a8ea39dc6e Модуль:Wikidata:Dictionary/P424 828 81 160 159 2025-01-25T21:00:33Z Vallenland 2 1 версия импортирована Scribunto text/plain return { Q143={'eo'}, Q150={'fr'}, Q188={'de'}, Q256={'tr'}, Q294={'is'}, Q328={'en'}, Q397={'la'}, Q652={'it'}, Q809={'pl'}, Q1321={'es'}, Q1412={'fi'}, Q1568={'hi'}, Q1571={'mr'}, Q1617={'ur'}, Q1860={'en'}, Q4627={'ay'}, Q5111={'ab'}, Q5137={'gu'}, Q5146={'pt'}, Q5218={'qu'}, Q5287={'ja'}, Q5885={'ta'}, Q6654={'hr'}, Q7026={'ca'}, Q7411={'nl'}, Q7737={'ru'}, Q7838={'sw'}, Q7850={'zh'}, Q7913={'ro'}, Q7918={'bg'}, Q7930={'mg'}, Q7979={'en-gb'}, Q8097={'te'}, Q8108={'ka'}, Q8447={'fr'}, Q8449={'es'}, Q8641={'yi'}, Q8748={'sq'}, Q8752={'eu'}, Q8765={'an'}, Q8785={'hy'}, Q8798={'uk'}, Q9027={'sv'}, Q9035={'da'}, Q9043={'no'}, Q9051={'lb'}, Q9056={'cs'}, Q9058={'sk'}, Q9063={'sl'}, Q9067={'hu'}, Q9072={'et'}, Q9078={'lv'}, Q9083={'lt'}, Q9091={'be'}, Q9129={'mis'}, Q9142={'ga'}, Q9166={'mt'}, Q9168={'fa'}, Q9176={'ko'}, Q9186={'zh-yue','yue'}, Q9199={'vi'}, Q9205={'km'}, Q9211={'lo'}, Q9217={'th'}, Q9228={'my'}, Q9237={'ms'}, Q9240={'id'}, Q9246={'mn'}, Q9252={'kk'}, Q9255={'ky'}, Q9260={'tg'}, Q9264={'uz'}, Q9267={'tk'}, Q9288={'he'}, Q9292={'az'}, Q9296={'mk'}, Q9299={'sr'}, Q9301={'sh'}, Q9303={'bs'}, Q9307={'gl'}, Q9309={'cy'}, Q9314={'gd'}, Q9610={'bn'}, Q10000={'nl'}, Q10134={'tlh'}, Q10179={'zu'}, Q10199={'diq'}, Q11059={'sa'}, Q11913={'bg'}, Q11918={'el'}, Q11920={'it'}, Q11921={'pt'}, Q12107={'br'}, Q12175={'gv'}, Q12237={'la'}, Q13198={'rcf'}, Q13199={'rm'}, Q13201={'rmy'}, Q13216={'za'}, Q13218={'xh'}, Q13238={'udm'}, Q13248={'hsb'}, Q13263={'ug'}, Q13267={'si'}, Q13275={'so'}, Q13286={'dsb'}, Q13293={'sma'}, Q13300={'nah'}, Q13307={'na'}, Q13310={'nv'}, Q13324={'min'}, Q13330={'mwl'}, Q13343={'mdf'}, Q13356={'mzn'}, Q13357={'fit'}, Q13358={'ruq'}, Q13359={'xmf'}, Q13389={'ba'}, Q13955={'ar'}, Q14185={'oc'}, Q14196={'af'}, Q14380={'sl'}, Q14549={'sco'}, Q15085={'pms'}, Q15087={'frp'}, Q17985={'ko'}, Q21117={'esu'}, Q22711={'pdc'}, Q23014={'pfl'}, Q25164={'nn'}, Q25167={'nb'}, Q25258={'fo'}, Q25285={'tt'}, Q25289={'kw'}, Q25355={'kl'}, Q25433={'nds'}, Q26245={'rue'}, Q27154={'stq'}, Q27175={'fy'}, Q27183={'ik'}, Q27683={'ace'}, Q27776={'ady'}, Q27811={'aa'}, Q28026={'ak'}, Q28224={'frr'}, Q28244={'am'}, Q28378={'anp'}, Q28602={'arc'}, Q29316={'roa-rup','rup'}, Q29401={'as'}, Q29507={'ast'}, Q29540={'bar'}, Q29561={'av'}, Q29919={'arz'}, Q29921={'iu'}, Q29952={'myv'}, Q30005={'ee'}, Q30007={'ext'}, Q30239={'zh'}, Q30319={'szl'}, Q31746={'lez'}, Q32145={'ksh'}, Q32641={'mis'}, Q32656={'dv'}, Q32704={'ve'}, Q32724={'vec'}, Q32747={'vep'}, Q32762={'fiu-vro','vro'}, Q32858={'vot'}, Q32979={'cho'}, Q33025={'bej'}, Q33081={'dz'}, Q33111={'co'}, Q33120={'bxr'}, Q33151={'bjn'}, Q33170={'ckt'}, Q33190={'bug'}, Q33202={'brh'}, Q33219={'map-bms'}, Q33239={'ceb'}, Q33243={'bm'}, Q33262={'ch'}, Q33265={'chy'}, Q33268={'bh','bho'}, Q33273={'ny'}, Q33281={'cbk-zam'}, Q33284={'bcl'}, Q33287={'gaa'}, Q33291={'fon'}, Q33295={'fj'}, Q33315={'hz'}, Q33348={'cv'}, Q33350={'ce'}, Q33357={'crh'}, Q33368={'lg'}, Q33375={'hak'}, Q33388={'chr'}, Q33390={'cr'}, Q33441={'fur'}, Q33454={'ff'}, Q33457={'gag'}, Q33475={'gan'}, Q33491={'ht'}, Q33509={'inh'}, Q33522={'kbd'}, Q33541={'kaa'}, Q33549={'jv'}, Q33552={'ks'}, Q33569={'haw'}, Q33573={'rw'}, Q33578={'ig'}, Q33583={'rn'}, Q33587={'ki'}, Q33617={'ho'}, Q33634={'xal'}, Q33657={'glk'}, Q33661={'mfe'}, Q33673={'kn'}, Q33690={'csb'}, Q33698={'liv'}, Q33702={'kg'}, Q33714={'krc'}, Q33720={'krj'}, Q33730={'arn'}, Q33754={'lmo'}, Q33786={'sid'}, Q33810={'or'}, Q33823={'ne'}, Q33845={'nap'}, Q33850={'nrm'}, Q33856={'pap'}, Q33864={'om'}, Q33879={'pag'}, Q33900={'ng'}, Q33947={'se'}, Q33954={'sg'}, Q33968={'os'}, Q33973={'scn'}, Q33976={'sc'}, Q33979={'new'}, Q33989={'srn'}, Q33997={'sd'}, Q34002={'su'}, Q34004={'sn'}, Q34011={'sm'}, Q34014={'ss'}, Q34015={'crs'}, Q34024={'pcd'}, Q34055={'tvl'}, Q34057={'tl'}, Q34094={'to'}, Q34119={'tyv'}, Q34124={'ti'}, Q34125={'tet'}, Q34128={'ty'}, Q34137={'tn'}, Q34138={'tum'}, Q34147={'vls'}, Q34159={'tpi'}, Q34208={'wbl'}, Q34219={'wa'}, Q34233={'ryu'}, Q34235={'ii'}, Q34247={'yai'}, Q34251={'tcy'}, Q34257={'wo'}, Q34271={'bo'}, Q34279={'war'}, Q34290={'wuu'}, Q34299={'sah'}, Q34311={'yo'}, Q34318={'tly'}, Q34327={'ts'}, Q34340={'st'}, Q35224={'io'}, Q35225={'peo'}, Q35452={'bi'}, Q35497={'grc'}, Q35499={'cu'}, Q35501={'prg'}, Q35722={'got'}, Q35744={'kri'}, Q35850={'ie'}, Q35853={'kab'}, Q35876={'gn'}, Q35934={'ia'}, Q35936={'ilo'}, Q35939={'jam'}, Q35963={'mis'}, Q35978={'hil'}, Q36094={'kr'}, Q36106={'lij'}, Q36109={'mai'}, Q36121={'pam'}, Q36126={'kv'}, Q36196={'lad'}, Q36206={'lbe'}, Q36212={'ltg'}, Q36217={'ln'}, Q36236={'ml'}, Q36280={'mh'}, Q36323={'pko'}, Q36350={'jbo'}, Q36368={'ku'}, Q36387={'mis'}, Q36392={'mo'}, Q36451={'mi'}, Q36455={'cdo'}, Q36495={'zh-min-nan','nan'}, Q36510={'el'}, Q36584={'olo'}, Q36699={'pis'}, Q36727={'pi'}, Q36730={'ota'}, Q36738={'nov'}, Q36748={'pnt'}, Q36811={'ckb'}, Q36850={'tw'}, Q36986={'vo'}, Q37041={'zh-classical','lzh'}, Q37059={'bpy'}, Q37178={'ine'}, Q38288={'diq'}, Q42365={'ang'}, Q44676={'en-ca'}, Q45041={'lez'}, Q46728={'hif'}, Q48183={'de'}, Q48952={'fa'}, Q53464={'hu'}, Q56240={'aeb'}, Q56318={'koi'}, Q56426={'ary'}, Q56475={'ha'}, Q56483={'lki'}, Q56499={'arq'}, Q56508={'sou'}, Q58172={'kk'}, Q58209={'ba'}, Q58215={'cv'}, Q58251={'az'}, Q58255={'tr'}, Q58635={'pa'}, Q58679={'sh'}, Q58680={'ps'}, Q58781={'rue'}, Q60786={'crh'}, Q60799={'ky'}, Q60819={'tt'}, Q60856={'ug'}, Q79633={'gag'}, Q79636={'kaa'}, Q102172={'li'}, Q131339={'als','gsw'}, Q146803={'lfn'}, Q155214={'id'}, Q169514={'sv'}, Q175482={'fi'}, Q177837={'ja'}, Q181037={'aln'}, Q181163={'da'}, Q182695={'mis'}, Q190551={'eo'}, Q191168={'cs'}, Q191769={'no'}, Q192582={'sk'}, Q199693={'ca'}, Q199698={'uk'}, Q199700={'ar'}, Q199864={'ro'}, Q199913={'he'}, Q200060={'et'}, Q200180={'vi'}, Q200183={'simple'}, Q200386={'sr','sr-ec','sr-el'}, Q202472={'lt'}, Q203488={'hr'}, Q206855={'ru'}, Q207260={'eu'}, Q208533={'sq'}, Q213434={'bat-smg','sgs'}, Q221444={'udm'}, Q225594={'sah'}, Q226150={'os'}, Q237409={'zea'}, Q242648={'eml'}, Q257829={'bqi'}, Q306626={'de-at'}, Q427715={'bn'}, Q497345={'vmf'}, Q511754={'tk'}, Q516137={'nds-nl'}, Q523014={'mus'}, Q547271={'cu'}, Q565074={'th'}, Q571001={'tpi'}, Q588620={'pam'}, Q595628={'oc'}, Q695526={'roa-tara'}, Q714826={'vo'}, Q718394={'is'}, Q722040={'hi'}, Q722243={'sw'}, Q728945={'lv'}, Q750553={'pt-br'}, Q766705={'af'}, Q824297={'mhr'}, Q837615={'ceb'}, Q841208={'gl'}, Q842341={'mk'}, Q844491={'ta'}, Q845993={'ms'}, Q846630={'cdo'}, Q846871={'br'}, Q848046={'te'}, Q848525={'cy'}, Q848974={'ka'}, Q856881={'myv'}, Q874555={'ml'}, Q875631={'ga'}, Q877583={'be'}, Q877685={'tl'}, Q880301={'frc'}, Q925661={'kv'}, Q928808={'dv'}, Q938216={'khw'}, Q940309={'szl'}, Q950058={'lb'}, Q966609={'su'}, Q1034940={'mrj'}, Q1047829={'bs'}, Q1047851={'nap'}, Q1055841={'vec'}, Q1058430={'scn'}, Q1066461={'ht'}, Q1067878={'ur'}, Q1071918={'ast'}, Q1110233={'wuu'}, Q1116066={'koi'}, Q1132977={'wa'}, Q1147071={'an'}, Q1148240={'yo'}, Q1154741={'ku'}, Q1154766={'io'}, Q1178461={'mdf'}, Q1190962={'zh-yue'}, Q1194341={'ru-sib'}, Q1211233={'als'}, Q1249553={'krc'}, Q1287192={'bpy'}, Q1291627={'new'}, Q1366643={'de-ch'}, Q1377618={'qu'}, Q1378484={'zh-classical'}, Q1389492={'pnb'}, Q1405077={'kj'}, Q1444686={'sco'}, }; c8444b1c598748668639bce6aaadca710aea0059 Шаблон:Doc 10 82 162 161 2025-01-25T21:00:33Z Vallenland 2 1 версия импортирована wikitext text/x-wiki <includeonly>{{doc/begin|{{SUBJECTSPACE}}:{{PAGENAME:{{{1|{{SUBJECTPAGENAME}}/doc}}}}}}} {{#if: {{{1|}}} | {{#ifexist: {{#if: {{NAMESPACE:{{{1}}}}} | {{{1}}} | {{SUBJECTSPACE}}:{{{1}}} }} | {{{{{1}}}|{{{2|}}}|{{{3|}}}|{{{4|}}}|{{{5|}}}}} | {{#ifexist: {{SUBJECTSPACE}}:{{{1}}} | {{{{{1}}}|{{{2|}}}|{{{3|}}}|{{{4|}}}|{{{5|}}}}} | {{Документировать|{{{1}}}}} }} }} | {{#ifexist: {{SUBJECTPAGENAME}}/doc | {{{{SUBJECTPAGENAME}}/doc}} | {{Документировать|{{SUBJECTPAGENAME}}/doc}} }} }} {{doc/end}}</includeonly><noinclude> {{doc}} </noinclude> 7298506ab2882f16fe7a52e0e080b2780b237bb9 Шаблон:Doc/begin 10 83 164 163 2025-01-25T21:00:33Z Vallenland 2 1 версия импортирована wikitext text/x-wiki <includeonly><templatestyles src="Шаблон:Doc/styles.css" /> <div class="ts-doc-doc" id="doc"> <div class="ts-doc-header" id="Документация"> <div class="ts-doc-heading">Документация</div> {{#if: {{{inline|}}} || {{Действия для страницы|lc={{{1}}}|nowatch=yes}} }} </div> <div class="ts-doc-content"></includeonly><noinclude> {{doc}} </noinclude> c753f0a9f65d86707cdffaf93fb49c2c52daf92b Шаблон:Doc/styles.css 10 84 166 165 2025-01-25T21:00:34Z Vallenland 2 1 версия импортирована text text/plain .ts-doc-doc { background-color: var(--background-color-progressive-subtle, #eaf3ff); border: 1px solid var(--border-color-content-added, #afb6e9); clear: both; margin-top: 1em; } /* Ctrl+F ":target" in [[MediaWiki:Common.css]] */ .ts-doc-doc sup.reference:target, .ts-doc-doc ol.references li:target, .ts-doc-doc .highlight-target:target, .ts-doc-doc cite:target, .ts-doc-doc span.citation:target { background: var(--ruwiki-background-color-blue200, #cfe3ff); } .ts-doc-header { align-items: center; background: var(--ruwiki-background-color-blue200, #cfe3ff); display: flex; flex-wrap: wrap; padding: .642857em 1em .5em; overflow: hidden; } .ts-doc-header .ts-tlinks-tlinks { margin-left: auto; } .ts-doc-content { padding: .214286em 1em; } .ts-doc-content:after { content: ''; clear: both; display: block; } .ts-doc-heading { display: inline-block; padding-left: 2em; background: url(//upload.wikimedia.org/wikipedia/commons/c/ca/OOjs_UI_icon_info.svg) center left no-repeat; background-size: contain; font-size: small; min-height: 1.75em; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; } @media screen { html.skin-theme-clientpref-night .ts-doc-heading { background-image: url(//upload.wikimedia.org/wikipedia/commons/c/c0/OOjs_UI_icon_info-invert.svg); } } @media screen and (prefers-color-scheme: dark) { html.skin-theme-clientpref-os .ts-doc-heading { background-image: url(//upload.wikimedia.org/wikipedia/commons/c/c0/OOjs_UI_icon_info-invert.svg); } } .ts-doc-content > *:first-child, .ts-doc-footer > *:first-child { margin-top: .5em; } .ts-doc-content > *:last-child, .ts-doc-footer > *:last-child { margin-bottom: .5em; } .ts-doc-footer { background-color: var(--background-color-progressive-subtle, #eaf3ff); border: 1px solid var(--border-color-content-added, #afb6e9); padding: .214286em 1em; margin-top: .214286em; margin-bottom: .214286em; font-style: italic; } @media (max-width: 719px) { .ts-doc-header { display: block; } .ts-doc-header .ts-tlinks-tlinks { float: none; } } /* [[Категория:Шаблоны:Подстраницы CSS]] */ be8d912472a37a6051bee114da86f913839e7ca0 Шаблон:Действия для страницы 10 85 168 167 2025-01-25T21:00:34Z Vallenland 2 1 версия импортирована wikitext text/x-wiki <templatestyles src="Шаблон:Действия для страницы/styles.css" /><div style="{{#ifeq: {{yesno-yes|{{{right|}}}}} | yes || float:none; }}" class="ts-tlinks-tlinks mw-editsection-like plainlinks"><span class="mw-editsection-bracket">[</span><!-- -->{{join|separator=<span class="mw-editsection-divider"> &amp;#124; </span> |1={{#ifexist: {{#rel2abs: {{{lc|}}} }} | {{#ifeq: {{{dislooklink|{{{noview|}}}}}} | yes || [[{{{lc}}}|просмотр]] }} }} |2={{#ifexist: {{#rel2abs: {{{lc|}}} }} | [[Special:EditPage/{{#rel2abs: {{{lc}}} }}|править]] }} |3={{#ifexist: {{#rel2abs: {{{lc|}}} }} | {{#ifeq: {{{dishistlink|{{{nohistory|}}}}}} | yes || [[Special:PageHistory/{{#rel2abs: {{{lc}}} }}|история]] }} }} |4={{#ifexist: {{#rel2abs: {{{lc|}}} }} | | [{{fullurl:{{#rel2abs: {{{lc}}} }}|action=edit&redlink=1}} создать] }} |5={{#ifeq: {{{diswatchlink|{{{nowatch|}}}}}} | yes || [{{fullurl:{{#rel2abs: {{{lc}}} }}|action=watch}} следить] }} |6={{#ifeq: {{{disupdlink|{{{noupdate|}}}}}} | yes || {{очистить кэш|обновить|nocat=1}}</span> }} }}<span class="mw-editsection-bracket">]</span></div><noinclude> {{doc}} </noinclude> 9ee2c9eed92e2ecc9377a7b9486ad8bc214a83d4 Шаблон:Действия для страницы/styles.css 10 86 170 169 2025-01-25T21:00:34Z Vallenland 2 1 версия импортирована text text/plain .ts-tlinks-tlinks { font-weight: normal; float: right; line-height: inherit; } .ts-tlinks-tlinks .mw-editsection-divider { display: inline; } /* [[Категория:Шаблоны:Подстраницы CSS]] */ a003e896d263c29e66d2246b210e5d73e577ea46 Шаблон:Doc/end 10 87 172 171 2025-01-25T21:00:34Z Vallenland 2 1 версия импортирована wikitext text/x-wiki <includeonly></div> </div><templatestyles src="Шаблон:Doc/styles.css" />{{#ifexpr: {{NAMESPACENUMBER}} mod 2 = 1 <!-- Например, [[Обсуждение MediaWiki:Robots.txt]] --> | {{^|1em}} | <div class="ts-doc-footer plainlinks"> {{#ifeq: {{str left|{{PAGENAME}}|9}} | Песочница | | {{#ifeq: {{str rightc|{{PAGENAME}}|10}} | /песочница | | Во избежание поломок страниц, использующих этот {{#ifeq: {{NAMESPACE}} | Модуль | модуль | шаблон }}, экспериментируйте в [[Википедия:Правка и тестирование шаблонов в песочнице|песочнице]] <small style="font-style:normal;">({{#ifexist: {{FULLPAGENAME}}/песочница | [{{fullurl:{{FULLPAGENAME}}/песочница|action=edit}} редактировать] {{!}} [{{fullurl:Special:ComparePages|page1={{FULLPAGENAMEE}}&page2={{FULLPAGENAMEE}}/песочница}} разница] {{#ifexist: {{FULLPAGENAME}}/тесты | {{!}} [[{{FULLPAGENAME}}/тесты|тесты]] }} | {{#ifeq: {{NAMESPACE}} | Модуль | [{{fullurl:{{FULLPAGENAME}}/песочница|action=edit}} создать] | [{{fullurl:{{FULLPAGENAME}}/песочница|action=edit&preload=Шаблон:Doc/предзагрузка-песочница}} создать] {{!}} [{{fullurl:{{FULLPAGENAME}}/песочница|action=edit&preload=Шаблон:Doc/зеркало}} зеркало] }} }})</small> или {{#ifeq: {{NAMESPACE}} | Модуль | [[Модуль:Песочница|песочнице для модулей]] | своём [[ВП:ЛП|личном пространстве]] }}.<br> }} }}{{#ifexist: {{FULLPAGENAME}}/doc | Пожалуйста, добавляйте категории на подстраницу [[/doc]].&#32;}}[[Special:PrefixIndex/{{FULLPAGENAME}}/|Подстраницы этого {{#ifeq: {{NAMESPACE}} | Модуль | модуля | шаблона }}]]. </div> }}</includeonly><noinclude>{{doc}}</noinclude> 758a01a3d76e14ef14b2b0ee047ac47ddac8fd8e Шаблон:Легенда 10 88 174 173 2025-01-25T21:00:34Z Vallenland 2 1 версия импортирована wikitext text/x-wiki <includeonly><!-- --><templatestyles src="Шаблон:Легенда/styles.css" /><!-- --><span class="ts-legend {{#ifeq: {{{3|}}} | inline | ts-legend-inline }} legend" style="{{#if: {{{8|}}} | font-size: {{{8}}}; }}"><!-- --><span class="ts-legend-color legend-color mw-no-invert {{{class|}}}" style="<!-- -->{{#if: {{{4|}}} | border: {{{4}}}; | {{#if: {{{1|}}} | border: 0px solid {{{1}}};}}}}<!-- -->{{#if: {{{5|}}} | border-radius: {{{5}}};}}<!-- -->{{#if: {{{1|}}} | background: {{{1}}};}}<!-- -->{{#if: {{{6|}}} | color: {{{6}}}; }}<!-- -->" {{#if: {{{9|}}} | title="{{{9}}}" | {{#if: {{{1|}}} | title="{{{1}}}"}} }}><!-- -->{{#if: {{{alt|}}}{{{7|}}} | <span class="ts-legend-text legend-text" style="{{#if:{{{alt|}}} | color:{{{1|}}};}}font-family: monospace, monospace;">{{#if: {{{7|}}} | {{{7}}} | &nbsp;&nbsp;&nbsp;&nbsp; }}</span> }}<!-- --></span><!-- -->&nbsp;{{{2|}}}<!-- --></span><!-- --></includeonly><noinclude> {{doc}} <!-- Пожалуйста, добавляйте категории и интервики на страницу документации! --> </noinclude> 362927ba47a0f5b2dcf9de3f17dbfbc8eaba4b89 Шаблон:Вложенные кавычки 10 89 176 175 2025-01-25T21:00:35Z Vallenland 2 1 версия импортирована wikitext text/x-wiki {{safesubst:<noinclude />#invoke:Вложенные кавычки|main}}<noinclude> {{doc}} </noinclude> 9ad9d29329e774649043f48fba384679babb4c08 Шаблон:Ombox 10 90 178 177 2025-01-25T21:00:35Z Vallenland 2 1 версия импортирована wikitext text/x-wiki {{#invoke:Message box|ombox}}<noinclude> {{doc}}<!-- Add categories and interwikis to the /doc subpage, not here! --></noinclude> ab34435c5ebc29de589c9b059e88da5d0e6f16e4 Шаблон:Цвет/Композитор.css 10 91 180 179 2025-01-25T21:00:35Z Vallenland 2 1 версия импортирована text text/plain .infobox-above, .infobox-header, .infobox-below { background: #bfe0bf; } @media screen { html.skin-theme-clientpref-night .infobox-above, html.skin-theme-clientpref-night .infobox-header { background: #224422; } html.skin-theme-clientpref-night .infobox-below { background: #182f18; } } @media screen and (prefers-color-scheme: dark) { html.skin-theme-clientpref-os .infobox-above, html.skin-theme-clientpref-os .infobox-header { background: #224422; } html.skin-theme-clientpref-os .infobox-below { background: #182f18; } } /* [[Категория:Шаблоны:Подстраницы CSS]] [[Категория:Шаблоны:Цвета по темам:Музыка|Композитор.css]] */ 174fb6f61c3dc1ef339cd4b496da585e1c4195d6 Шаблон:Cl 10 92 182 181 2025-01-25T21:00:35Z Vallenland 2 1 версия импортирована wikitext text/x-wiki <templatestyles src="Модуль:Template call code/styles.css" />{{#if: {{{2|}}} | <span class="ts-templateCallCode-weak"><nowiki>[[</nowiki>Категория:[[:Категория:{{{1}}}|{{{1}}}]]<nowiki>]]</nowiki></span> | [[:Категория:{{{1}}}|{{{1}}}]] }}<noinclude>{{doc}}</noinclude> 3f315bb5453e2a3ef5f031e946f35c568b49f8b4 Шаблон:Docpage 10 93 184 183 2025-01-25T21:00:36Z Vallenland 2 1 версия импортирована wikitext text/x-wiki <includeonly>{{#ifeq: {{SUBPAGENAME}} | doc | {{fmbox | class = hlist nowraplinks | style = margin-bottom:1em; background:var(--background-color-progressive-subtle, #eaf3ff); color:inherit; border:1px solid var(--border-color-content-added, #a3d3ff); | image = [[Файл:OOjs UI icon info.svg|24px|link=|alt=|class=skin-invert-image]] | text = <div> * [[:{{#titleparts: {{SUBJECTPAGENAME}} | -1 }}]] * [[:{{SUBJECTPAGENAME}}|Документация]] * [[{{#titleparts: {{TALKPAGENAME}} | -1 }}|Обсуждение]] * [[Служебная:Whatlinkshere/{{#titleparts: {{SUBJECTPAGENAME}} | -1 }}|Где используется]] {{#ifeq: {{NAMESPACE}} | {{ns:Template}} | ** {{Параметры шаблона|{{#titleparts: {{PAGENAME}} | -1 }}}} }}</div><!-- -->{{#if: {{{nocat|}}} || {{#ifexist: {{NAMESPACE}}:{{BASEPAGENAME}} || [[Категория:Шаблоны:Документация несуществующих шаблонов]] }} }} }}{{#if: {{{nocat|}}} || {{#ifeq: {{NAMESPACE}} | Модуль | [[Категория:Модули:Документация]] | [[Категория:Шаблоны:Документация]] }}__EXPECTED_UNCONNECTED_PAGE__ }} }}</includeonly><noinclude>{{doc}}</noinclude> e2d07566c50be35ac409e8396893a3b9d8676e0c Шаблон:Очистить кэш 10 94 186 185 2025-01-25T21:00:36Z Vallenland 2 1 версия импортирована wikitext text/x-wiki <!-- Класс purgelink и атрибут data-pagename используются в [[MediaWiki:Common.js]], чтобы очищать кэш без перехода на отдельную страницу --><span class="noprint purgelink" {{#if: {{{2|}}} | data-pagename="{{{2}}}" }}>{{выполнить скрипт|purgeLink}}[[Special:Purge/{{#if: {{{2|}}} | {{{2}}} | {{FULLPAGENAME}} }}|{{#if: {{{1|}}} | {{{1}}} | Очистить кэш }}]]</span>{{#ifeq: {{NAMESPACE}}{{{nocat|}}} | {{ns:10}} <!-- Шаблон --> | {{очищать кэш|ежедневно}} }}<noinclude>{{doc}}</noinclude> be6695060ca61d2125386d02d3a19109c0e7c27b Шаблон:Установлена проверка на неизвестные параметры 10 95 188 187 2025-01-25T21:00:36Z Vallenland 2 1 версия импортирована wikitext text/x-wiki {{ombox |name = Установлена проверка на неизвестные параметры |text = В этом шаблоне установлена [[Модуль:Check for unknown parameters|проверка на неизвестные параметры]], добавляющая страницы в {{c|{{#if:{{{категория|}}}|{{{категория|}}}|Страницы с неизвестными параметрами шаблона {{ROOTPAGENAME}}}}|В}}. |type = notice }}<includeonly>{{no-doc|[[Категория:Шаблоны с установленной проверкой на неизвестные параметры]]{{#ifexist: Категория:{{#if:{{{категория|}}}|{{{категория|}}}|Страницы с неизвестными параметрами шаблона {{ROOTPAGENAME}}}} || [[Категория:Шаблоны с установленной проверкой на неизвестные параметры и несуществующей категорией]] }}|nocat={{{nocat|}}}}}</includeonly><noinclude>{{doc-inline}} См. [[Модуль:Check for unknown parameters]] и [[:Категория:Википедия:Неизвестные параметры шаблонов]]. Добавляет {{Категория с размером|Шаблоны с установленной проверкой на неизвестные параметры и несуществующей категорией}}. [[Категория:Шаблоны:Предупреждения]] [[Категория:Шаблоны:Для документирования шаблонов]] {{doc-end}} </noinclude> cd47e06eec53b65393adba1f3143d6cd3d6cc54c Шаблон:C 10 96 190 189 2025-01-25T21:00:36Z Vallenland 2 1 версия импортирована wikitext text/x-wiki {{#switch: {{{2}}} | Р = {{{к|к}}}атегории | Д = {{{к|к}}}атегории | В = {{{к|к}}}атегорию | Т = {{{к|к}}}атегорией | П = {{{к|к}}}атегории | ю = {{{к|к}}}атегорию | ей | й = {{{к|к}}}атегорией | и = {{{к|к}}}атегории | {{{к|к}}}атегория }} «[[:Категория:{{{1}}}|{{вложенные кавычки|{{{1}}}}}]]»<noinclude>{{doc}}</noinclude> 29dc241d0737db87ea05ae164b21b3bdc0da3f83 Шаблон:Цвет/Инструменталист.css 10 97 192 191 2025-01-25T21:00:37Z Vallenland 2 1 версия импортирована text text/plain .infobox-above, .infobox-header, .infobox-below { background: #f4bf92; } @media screen { html.skin-theme-clientpref-night .infobox-above, html.skin-theme-clientpref-night .infobox-header, html.skin-theme-clientpref-night .infobox-below { background: #3f200f; } } @media screen and (prefers-color-scheme: dark) { html.skin-theme-clientpref-os .infobox-above, html.skin-theme-clientpref-os .infobox-header, html.skin-theme-clientpref-os .infobox-below { background: #3f200f; } } /* [[Категория:Шаблоны:Подстраницы CSS]] [[Категория:Шаблоны:Цвета по темам:Музыка|Инструменталист.css]] */ face7b56fa576807b9a51c764a3ac3b0f878ec82 Шаблон:OnLua 10 98 194 193 2025-01-25T21:00:37Z Vallenland 2 1 версия импортирована wikitext text/x-wiki #перенаправление [[Шаблон:Lua]] b72371e7ae22239863c474a78238171c2bd94c7e Шаблон:Музыкант/цвет/схема 10 99 196 195 2025-01-25T21:00:37Z Vallenland 2 1 версия импортирована wikitext text/x-wiki <includeonly>{{#switch:{{lc:{{{1|}}}}}<!-- -->|solo_singer |вокалист=Вокалист<!-- -->|non_vocal_instrumentalist |инструменталист=Инструменталист<!-- -->|non_performing_personnel |композитор |продюсер |дирижёр=Композитор<!-- -->}}</includeonly><noinclude> {{doc}} </noinclude> 0fc69c91f5ef446372370b02ac2ddf786f06c3d5 Шаблон:Выполнить скрипт 10 100 198 197 2025-01-25T21:00:37Z Vallenland 2 1 версия импортирована wikitext text/x-wiki {{#switch: {{{1|}}} | = | mainPage = [[Категория:Википедия:Заглавная страница|{{NAMESPACENUMBER}}]] | #default = {{#ifexist: Категория:Википедия:Страницы с гаджетом по требованию {{{1}}} | [[Категория:Википедия:Страницы с гаджетом по требованию {{{1}}}|{{NAMESPACENUMBER}}]] }} }}<noinclude> {{doc}} </noinclude> 6979ea0342067dc76b9adcb9a5e072207c2c5a63 Шаблон:OnLua/Строка 10 101 200 199 2025-01-25T21:00:37Z Vallenland 2 1 версия импортирована wikitext text/x-wiki #перенаправление [[Шаблон:Lua/Строка]] d7f869ccc7a7efc800399fce32bc75e0f91066de Шаблон:Заготовка шаблона 10 102 202 201 2025-01-25T21:00:38Z Vallenland 2 1 версия импортирована wikitext text/x-wiki {{#invoke:TemplateDataDoc|generateBlank|{{#if:{{{1|}}}|{{{1}}}|{{BASEPAGENAME}}}}|description={{{описание|}}}}}<noinclude>{{doc}}</noinclude> b451404244fd6898bc134564ddcb8941eca7f64a Модуль:TemplateDataDoc 828 103 204 203 2025-01-25T21:00:38Z Vallenland 2 1 версия импортирована Scribunto text/plain require( 'strict' ); local docSubPage = mw.message.new( 'Templatedata-doc-subpage' ):plain(); local p = {}; local lastNumber = 0; -- Enable/disable additional spacing for block-formatted templates local formatBlockSpaces = true; -- Params that should not be shown in code local deprecatedParams = { 'nocat', 'from', 'nocoord', 'nocatcoord', 'Автооформление заголовка', 'автооформление заголовка', 'Ширина', 'ширина', 'Ширина изображения', 'ширина изображения', 'Ширина логотипа', 'ширина логотипа', 'Ширина автографа', 'ширина автографа', }; local noDocNote = 'TemplateDataDoc: Запишите страницу для отображения заполненного шаблона.'; function p.processJson( json ) local status, data = pcall( mw.text.jsonDecode, json ); if status == false then return nil; end if not data[ 'paramOrder' ] then data[ 'paramOrder' ] = {}; for paramName, paramData in pairs( data[ 'params' ] ) do table.insert( data[ 'paramOrder' ], paramName ); end end for _, param in ipairs( deprecatedParams ) do if data[ 'params' ][ param ] ~= nil then data[ 'params' ][ param ][ 'deprecated' ] = '-'; end end return data; end function p.getTemplateData( pageName ) local title = mw.title.makeTitle( 0, pageName ); if not title or not title.exists then return false end local content = title:getContent() if not content then return false; end; local json = mw.ustring.match( content, '<[Tt]emplate[Dd]ata%s*>(.*)</[Tt]emplate[Dd]ata%s*>' ); if not json then return nil; end return p.processJson( json ) end function p.getValue( data, key ) if data[ key ] then return data[ key ]; end -- Numbered keys return as numbers local nkey = tonumber( key ); if nkey ~= nil and data[ nkey ] then return data[ nkey ]; end return {}; end -- See https://phabricator.wikimedia.org/diffusion/ETDA/browse/master/Specification.md?as=remarkup -- We need a global format value for the 'block' and 'inline': [[phab:T205438]] function p.convertFormatString( rawTemplateFormat ) local formatType = rawTemplateFormat or 'inline'; local templateFormat = formatType; local isBlockFormatted = false; if formatType == 'block' then templateFormat = '{{_\n| _ = _\n}}'; isBlockFormatted = true; elseif formatType == 'inline' then templateFormat = '{{_|_=_}}'; end return templateFormat, isBlockFormatted, formatType; end function p.getFormatParts( rawTemplateFormat, templateName ) local templateFormat, isBlockFormatted, formatType = p.convertFormatString( rawTemplateFormat ); local nameFormat = mw.ustring.match( templateFormat, '^[^|]+' ); local paramKeyFormat = mw.ustring.match( templateFormat, '%|[^=]+=' ); local paramValueFormat = mw.ustring.match( templateFormat, '=[^}]+' ); paramValueFormat = mw.ustring.sub( paramValueFormat, 2 ); local endFormat = mw.ustring.match( templateFormat, '%}%}.*$' ); local startFormat = mw.ustring.gsub( nameFormat, '_', templateName ); return isBlockFormatted, formatType, startFormat, endFormat, paramKeyFormat, paramValueFormat; end function p.formatKeyValue( key, parameterData, formatData ) if parameterData[ 'deprecated' ] then return ''; end local args = formatData.args; local parameterName = key; local nkey = tonumber( key ); -- Add additional spacing to string keys if formatBlockSpaces and formatData.parameterLength and formatData.formatType ~= 'inline' and ( nkey == nil or lastNumber ~= nkey - 1 ) then while mw.ustring.len( key ) < formatData.parameterLength do key = key .. ' '; end end -- Remove numbering for adjacent numbered keys if nkey ~= nil and lastNumber == nkey - 1 then key = ''; lastNumber = nkey; end local value = ''; if formatData.valueKey == 'example' and parameterData[ 'example' ] then -- Example value = parameterData[ 'example' ]; else if formatData.valueKey == 'description' and parameterData[ 'description' ] then -- Description value = parameterData[ 'description' ]; if value ~= '' then value = '<!-- ' .. value .. ' -->'; end elseif parameterData[ 'autovalue' ] then -- Autovalue value = parameterData[ 'autovalue' ]; end if args[ '$' .. parameterName ] and args[ '$' .. parameterName ] ~= '' then -- Custom values from template call value = args[ '$' .. parameterName ]; end end local formattedKey = mw.ustring.gsub( formatData.paramKeyFormat, '_+', key, 1 ); if key == '' then formattedKey = mw.ustring.gsub( formattedKey, '=', '' ); end return formattedKey .. mw.ustring.gsub( formatData.paramValueFormat, '_', value, 1 ); end function p.generateBlankCode( templateData, templateName, args ) if templateData == false then return '{{' .. templateName .. '}}'; end local parameterLength = 0; for i, parameterName in ipairs( templateData[ 'paramOrder' ] ) do local parameterData = p.getValue( templateData[ 'params' ], parameterName ); if not parameterData[ 'deprecated' ] then local length = mw.ustring.len( parameterName ); if length > parameterLength then parameterLength = length; end end end local isBlockFormatted, formatType, startFormat, endFormat, paramKeyFormat, paramValueFormat = p.getFormatParts( templateData[ 'format' ], templateName ); local out = startFormat; lastNumber = 0; for i, parameterName in ipairs( templateData[ 'paramOrder' ] ) do local parameterData = p.getValue( templateData[ 'params' ], parameterName ); if parameterData[ 'inherits' ] then parameterData = p.getValue( templateData[ 'params' ], parameterData[ 'inherits' ] ); end out = out .. p.formatKeyValue( parameterName, parameterData, { args = args, valueKey = ( args[ 'description' ] and 'description' or nil ), formatType = formatType, isBlockFormatted = isBlockFormatted, parameterLength = parameterLength, paramKeyFormat = paramKeyFormat, paramValueFormat = paramValueFormat, } ); end return out .. endFormat; end function p.generateBlank( frame ) local frame = mw.getCurrentFrame(); local getArgs = require( 'Module:Arguments' ).getArgs; local args = getArgs( frame ); local templateName = frame.args[ 1 ]; table.remove( args, 1 ); local docPage = 'Template:' .. templateName .. '/' .. docSubPage; local templateData = p.getTemplateData( docPage ); local out = p.generateBlankCode( templateData, templateName, args ); local previewNote = '' if templateData == false and frame:preprocess('{{REVISIONID}}') == '' then previewNote = '<div class="warningbox">' .. noDocNote .. '</div>'; end return previewNote .. frame:extensionTag{ name = 'syntaxhighlight', args = { lang = 'html', copy = true }, content = out, }; end function p.generateExampleCode( templateData, templateName, args ) if templateData == false then return '{{' .. templateName .. '}}'; end local parameterLength = 0; for i, parameterName in ipairs( templateData[ 'paramOrder' ] ) do local parameterData = p.getValue( templateData[ 'params' ], parameterName ); if parameterData[ 'example' ] and not parameterData[ 'deprecated' ] then local length = mw.ustring.len( parameterName ); if length > parameterLength then parameterLength = length; end end end local isBlockFormatted, formatType, startFormat, endFormat, paramKeyFormat, paramValueFormat = p.getFormatParts( templateData[ 'format' ], templateName ); local out = startFormat; lastNumber = 0; for i, parameterName in ipairs( templateData[ 'paramOrder' ] ) do local parameterData = p.getValue( templateData[ 'params' ], parameterName ); if parameterData[ 'inherits' ] then parameterData = p.getValue( templateData[ 'params' ], parameterData[ 'inherits' ] ); end if parameterData[ 'example' ] then out = out .. p.formatKeyValue( parameterName, parameterData, { args = args, valueKey = 'example', formatType = formatType, isBlockFormatted = isBlockFormatted, parameterLength = parameterLength, paramKeyFormat = paramKeyFormat, paramValueFormat = paramValueFormat, } ); end end return out .. endFormat; end function p.generateExample( frame ) local frame = mw.getCurrentFrame(); local args = frame.args; local templateName = frame.args[ 1 ]; local docPage = 'Template:' .. templateName .. '/' .. docSubPage; local templateData = p.getTemplateData( docPage ); local out = p.generateExampleCode( templateData, templateName, args ); local previewNote = '' if templateData == false and frame:preprocess('{{REVISIONID}}') == '' then previewNote = '<div class="warningbox">' .. noDocNote .. '</div>'; end return previewNote .. frame:preprocess( out ) .. frame:extensionTag{ name = 'syntaxhighlight', args = { lang = 'html' }, content = out, }; end return p; 8134c68a67c62ea08db535b9110981288d627bbd Шаблон:Старый-новый стиль,примечание 10 104 206 205 2025-01-25T21:00:39Z Vallenland 2 1 версия импортирована wikitext text/x-wiki В случае, если дата рождения/смерти в источниках приведена по [[Юлианский календарь|старому стилю]], рекомендуется указывать её по новому стилю, а после указать в скобках отличающуюся часть даты по старому стилю. Например, * «13.05.1801 (1)» будет отображено как [[13 мая|1 (13) мая]] [[1801 год|1801]]; * «12.06.1801 (31.05)» будет отображено как 31 мая ([[12 июня]]) [[1801 год|1801]]; * «12.01.1802 (31.12.1801)» будет отображено как 31 декабря 1801 ([[12 января]] [[1802 год|1802]]). При этом в статью будут автоматически подставлены категории даты рождения/смерти по ''новому'' стилю. Учтите, что разница между датами нового и старого стиля составляет 13 дней в XX и XXI веках, 12 дней в XIX веке, 11 дней в XVIII веке, 10 дней в XVII и XVI веках (начиная с 5 (15) октября 1582 года).<noinclude>{{doc-inline}}Шаблон предназначен для подстановки в качестве примечания к полям «дата рождения», «дата смерти» для страниц документации шаблонов-карточек типа «Персона». Параметров не принимает. Вызов: {{tl|Старый-новый стиль,примечание}} {{doc-end}} [[Категория:Википедия:Шаблоны, встраиваемые в шаблоны-карточки:Личности]] </noinclude> 7f8754eb5c2401671df545a1cd8b315f66f86463 Шаблон:Lua 10 105 208 207 2025-01-25T21:00:39Z Vallenland 2 1 версия импортирована wikitext text/x-wiki <includeonly>{{ombox | small = yes | style = width:23em; | image = [[Файл:Lua-logo-nolabel.svg|40px|alt=|link=]] | text = {{replace|Этот шаблон {{#if: {{{partly|}}} | частично }} реализован на основе [[Lua]]{{#if:{{{module2|}}}{{{tech2|}}}|&#58;<br><ul><li>}}{{#if:{{{1|}}}{{{tech|}}}|&#32;с использованием {{{tech|{{#if:{{{2|}}}|функции <code>{{#if:{{{line|}}}|[[Module:{{{1}}}#L-{{{line}}}|{{{2}}}()]]|[[{{{funcref|Module:{{{1}}}#{{{2}}}}}}|{{{2}}}()]]}}</code> из&#32;}}{{#if:{{{1|}}}|модуля [[Module:{{{1}}}|{{{1}}}]]}}}}};}}<!-- -->{{#invoke:Transclude|npc|OnLua/Строка| module= |function= |tech= |line= }}.|;.|.}}{{#if:{{{module2|}}}{{{tech2|}}}|</ul>}} {{#if:{{{1|}}}{{{tech|}}}{{{module1|}}}{{{tech1|}}}||<div class="error"><small>'''Не указано название использующегося модуля!'''</small></div>}} }}{{#ifeq:{{SUBPAGENAME}}|{{{doc|doc}}}||{{#if:{{{nocat|}}}||[[Категория:Шаблоны, использующие Scribunto]]{{#if:{{{1|}}}{{{tech|}}}{{{module1|}}}{{{tech1|}}}||[[Категория:Шаблоны, использующие Lua, без указания модуля]]}}}}}}</includeonly><noinclude>{{doc}}</noinclude> f1fdaa87edb15d61e23e98f6e25d171a975e10eb Шаблон:Музыкант/doc 10 106 210 209 2025-01-25T21:00:41Z Vallenland 2 1 версия импортирована wikitext text/x-wiki {{docpage}}{{OnLua|partly=1|module1=Wikidata/Interproject|module2=CategoryForProfession}} {{Установлена проверка на неизвестные параметры}} [[Википедия:Шаблоны-карточки|Шаблон-карточка]] {{tl|Музыкант}} должен присутствовать в начале статей о певцах, композиторах, дирижёрах и других музыкальных деятелях. Для музыкальных коллективов есть специальный шаблон {{tl|Музыкальный коллектив}}. == Использование == {{Parameter names example|Фон|Имя|Оригинал имени|Изображение|Ширина|Описание изображения|Имя при рождении|Полное имя|Дата рождения|Место рождения|Дата смерти|Место смерти|Похоронен|Страна|Профессии|Годы активности|Певческий голос|Инструменты|Жанры|Псевдонимы|Коллективы|Лейбл текст|Лейблы|Награды|Логотип|Ширина логотипа|Сайт}} {{Заготовка шаблона|$Оригинал имени = <nowiki>{{lang-XX|}}</nowiki>}} == Описание параметров == # <code>Фон</code> — специализация, наиболее отражающая деятельность персоналии (см. подробности в {{tl|Музыкант/цвет}}): ::: {{Легенда|#f0e68c|'''вокалист''' — вокалист}} ::: {{Легенда|#f4bf92|'''инструменталист''' — музыкант, играющий на инструментах, но не поющий}} ::: {{Легенда|#bfe0bf|'''композитор''' — музыкант, не поющий и не играющий на инструментах (синонимы: '''дирижёр''', '''продюсер''')}} # <code>Имя</code> — имя музыканта на русском языке. # <code>Оригинал имени</code> — имя на официальном языке страны рождения в формате <code><nowiki>{{lang-код языка|имя}}</nowiki></code> (для русского языка — заполнять не следует). # <code>Изображение</code> — имя файла с фотографией музыканта (см. ''[[Википедия:Иллюстрирование]]''). # <code>Ширина</code> — ширина фото (обычно нет причины это менять). # <code>Описание изображения</code> — где и когда сделано фото. Не сто́ит дублировать в этом поле имя музыканта: если о фотографии ничего не известно, просто не заполняйте это поле. # <li value=7> <code>Имя при рождении</code> — следует заполнять в случае, если имя музыканта, указанное в параметре <code>Имя</code>, не принадлежало ему с рождения. Для указания полного имени нужно использовать поле <code>Полное имя</code> (''см. ниже'').</li> # <code>Полное имя</code> — полное имя музыканта, если в поле <code>Имя</code> используется сокращённое имя. # <code>Дата рождения</code> — дата рождения музыканта в формате дд.мм.гггг — например, <code><nowiki>31.12.1945</nowiki></code>. # <code>Место рождения</code> — место рождения музыканта — например, <code><nowiki>{{МестоРождения|Лондон}}</nowiki></code>. Можно использовать шаблон {{tl|МестоРождения}}. # <code>Дата смерти</code> — дата смерти музыканта в формате дд.мм.гггг (для ныне живущих, естественно, не заполняется). О датах по старому стилю см. примечание ниже. # <code>Место смерти</code> — место смерти музыканта. Можно использовать шаблон {{tl|МестоСмерти}}. # <code>Похоронен</code> — место захоронения музыканта. # <code>Страна</code> — гражданство исполнителя; указывается просто название страны, без каких-либо шаблонов. # <code>Профессии</code> — сферы музыкальной деятельности — например, <code><nowiki>{{певец|России|XX века|XXI века}}</nowiki></code>, <code><nowiki>{{поэт|России|XX века|XXI века}}</nowiki></code> # <code>Годы активности</code> — годы активности музыканта. # <code>Певческий голос</code> — Заполняется для оперных певцов и певиц. см. [[Певческие голоса]]. # <code>Инструменты</code> — основные музыкальные инструменты (для инструменталистов). # <code>Жанры</code> — основные [[Список музыкальных жанров, направлений и стилей|жанры]], в которых пел/играл музыкант. # <code>Псевдонимы</code> — [[псевдоним]]ы, под которыми известен музыкант. # <code>Коллективы</code> — коллективы, в которых музыкант принимал участие. # <code>Лейблы</code> — названия [[Лейбл звукозаписи|лейблов]], где издавался музыкант. # <code>Награды</code> — государственные награды, имеющиеся у музыканта. # <code>Логотип</code> — личный логотип музыканта (не группы, в которую он входит). # <code>Ширина логотипа</code> — ширина логотипа (обычно нет причины это менять). # <code>Сайт</code> — ссылка на официальный сайт музыканта. === Примечания === # Незаполненные поля не отображаются при выводе шаблона. Те из них, которые в принципе не могут быть заполнены (например, <code>Певческий голос</code> для не-певцов), нужно стирать. # Если возникла необходимость изменить стандартные размеры фотографии, используйте параметр <code>Ширина</code>. Например, <code>{{nobr|1=Ширина = 250пкс}}</code>. Не рекомендуется использовать значения выше 300 # Шаблон автоматически добавляет включающую его статью в категории «{{cl|Музыканты по алфавиту}}» и «{{cl|Персоналии по алфавиту}}». # Если в статье речь идёт об анонимном музыканте, известном только под псевдонимом, то в поля <code>Имя</code> записывается псевдоним. # {{Старый-новый стиль,примечание}} == Примеры использования == {| style="background: transparent; color: inherit" |- valign="top" | {{Музыкант | Имя = Иоганн Себастьян Бах | Оригинал имени = {{lang-de|Johann Sebastian Bach}} | Изображение = JSBach.jpg | Описание изображения = Портрет Баха (1748) | Фон = композитор | Дата рождения = 21.03.1685 | Место рождения = [[Айзенах]] | Дата смерти = 28.07.1750 | Место смерти = [[Лейпциг]] | Страна = {{Флагификация|Германия}} | Профессии = [[композитор]], [[органист]] | Инструменты = [[Орган (музыкальный инструмент)|орга́н]] | Жанры = [[классическая музыка]] }} | {{Музыкант | Имя = Джон Андерсон | Оригинал имени = {{lang-en|Jon Anderson}} | Изображение = Jon anderson 1977.jpg | Описание изображения = На концерте [[Yes (группа)|Yes]] в [[Индианаполис]]е ([[1977 в музыке|1977]]) | Фон = вокалист | Полное имя = Джон Рой Андерсон | Дата рождения = 25.10.1944 | Место рождения = [[Аккрингтон]], [[Ланкашир]], [[Англия]] | Страна = {{Флагификация|Великобритания}} | Профессии = [[певец]], [[музыкант]] | Жанры = [[прогрессивный рок]], [[нью-эйдж]] | Коллективы = [[Yes (группа)|Yes]], [[Anderson Bruford Wakeman Howe|ABWH]], [[Jon & Vangelis]] | Сайт = jonanderson.com }} | {{Музыкант | Имя = Джимми Пэйдж | Оригинал имени = {{lang-en|Jimmy Page}} | Изображение = Джимми Пэйдж.jpg | Фон = инструменталист | Полное имя = James Patrick Page | Дата рождения = 09.01.1944 | Место рождения = Хестон, [[Лондон]], [[Англия]] | Страна = {{Флагификация|Великобритания}} | Профессии = * [[Гитарист]] * [[Музыкальный продюсер|продюсер]] | Инструменты = [[Gibson Les Paul]] * [[Gibson EDS-1275]] * [[Danelectro 59 DC]] * [[Fender Telecaster]] | Жанры = * [[хард-рок]] * [[блюз-рок]] * [[фолк-рок]] * [[Прогрессивный рок|прогрессив]] * [[хэви-метал]] | Псевдонимы = ZoSo | Коллективы = * [[The Yardbirds]] * [[Led Zeppelin]] * [[The Honeydrippers]] * [[The Firm]] * [[Coverdale-Page]] * [[Page and Plant]] * [[XYZ (группа)|XYZ]] | Лейблы = * [[Swan Song]] * [[Atlantic Records]] | Сайт = jimmypageonline.com }} |} == TemplateData == <templatedata> { "description": "Карточка для статей о певцах, композиторах, дирижёрах и других музыкальных деятелях", "params": { "Страна": { "label": "Страна", "description": "Гражданство музыканта. Указывается просто название страны, без каких-либо шаблонов; если стран несколько, они перечисляются через запятую. Может подставляться из Викиданных.", "type": "content" }, "Фон": { "label": "Фон", "description": "Цвет фона карточки. Допустимые значения: «вокалист» — вокалист; «инструменталист» — музыкант, играющий на инструментах, но не поющий; «композитор» — музыкант, не поющий и не играющий на инструментах (синонимы: «дирижёр», «продюсер»).", "type": "line", "suggestedvalues": [ "вокалист", "инструменталист", "композитор", "дирижёр", "продюсер" ] }, "Имя": { "label": "Имя", "description": "Имя музыканта на русском языке. Если в статье речь идёт об анонимном музыканте, известном только под псевдонимом, то в поля «Имя» записывается псевдоним.", "type": "string", "default": "Название страницы", "required": true }, "Оригинал имени": { "label": "Оригинал имени", "description": "Имя музыканта на официальном языке страны рождения, если отличается от языка в заголовке карточки. Оборачивается в один из языковых шаблонов {{lang-XX}}.", "example": "{{lang-de|Johann Sebastian Bach}}", "type": "content" }, "Изображение": { "label": "Изображение", "description": "Имя файла с фотографией музыканта. Может подставляться из Викиданных.", "type": "wiki-file-name" }, "Ширина": { "label": "Ширина", "description": "Ширина изображения. Не рекомендуется использовать значения выше 300.", "type": "number" }, "Описание изображения": { "label": "Описание изображения", "description": "Подпись к изображению, например где и когда сделано фото.", "type": "line" }, "Имя при рождении": { "label": "Имя при рождении", "description": "Следует заполнять в случае, если имя музыканта, указанное в параметре «Имя», не принадлежало ему с рождения.", "type": "content" }, "Полное имя": { "label": "Полное имя", "description": "Полное имя музыканта, если в поле «Имя» используется сокращённое имя.", "type": "content" }, "Дата рождения": { "label": "Дата рождения", "description": "Дата рождения музыканта в формате дд.мм.гггг, например 31.12.1945. Может подставляться из Викиданных. О датах по старому стилю см. примечание ниже.", "type": "date" }, "Дата смерти": { "label": "Дата смерти", "description": "Дата смерти музыканта в формате дд.мм.гггг (для ныне живущих, естественно, не заполняется). Может подставляться из Викиданных.", "type": "date" }, "Место рождения": { "label": "Место рождения", "description": "Место рождения музыканта — например, {{Место рождения|Лондон}}. Можно использовать шаблон {{МестоРождения}}. Может подставляться из Викиданных.", "type": "content" }, "Место смерти": { "label": "Место смерти", "description": "Место смерти музыканта. Можно использовать шаблон {{МестоСмерти}}. Может подставляться из Викиданных.", "type": "content" }, "Профессии": { "label": "Профессии", "description": "Сферы музыкальной деятельности — например, {{певец|России|XX века|XXI века}}, {{поэт|России|XX века|XXI века}}. Может подставляться из Викиданных.", "type": "content" }, "Годы активности": { "label": "Годы активности", "description": " Годы активности музыканта.", "type": "string", "example": "1999—2005, 2006 — {{нв}}" }, "Певческий голос": { "label": "Певческий голос", "description": "Заполняется для оперных певцов и певиц.", "type": "content" }, "Инструменты": { "label": "Инструменты", "description": "Основные музыкальные инструменты (для инструменталистов).", "type": "content" }, "Жанры": { "label": "Жанры", "description": "Основные жанры, в которых пел/играл музыкант.", "type": "content" }, "Псевдонимы": { "label": "Псевдонимы", "description": "Псевдонимы, под которыми известен музыкант.", "type": "content" }, "Коллективы": { "label": "Коллективы", "description": "Коллективы, в которых музыкант принимал участие.", "type": "content" }, "Лейбл текст": { "label": "Лейбл текст", "description": "Подменяет название строки «Лейблы» на указанное.", "type": "string" }, "Лейблы": { "label": "Лейблы", "description": "Названия лейблов, где издавался музыкант.", "type": "string" }, "Награды": { "label": "Награды", "description": "Государственные награды, имеющиеся у музыканта.", "type": "unbalanced-wikitext" }, "Логотип": { "label": "Логотип", "description": "Имя файла с логотипом музыканта (не группы, в которую он входит). Может подставляться из Викиданных.", "type": "wiki-file-name" }, "Ширина логотипа": { "label": "Ширина логотипа", "description": "Ширина логотипа. Не рекомендуется использовать значения выше 300.", "type": "number" }, "Сайт": { "label": "Сайт", "description": "Ссылка на официальный сайт музыканта. Может подставляться из Викиданных.", "type": "url" }, "Викисклад": { "label": "Викисклад", "description": "Ссылка на категорию о музыканте на Викискладе. Может подставляться из Викиданных.", "type": "line", "deprecated": "Заполняется автоматически из Викиданных" }, "Викитека": { "label": "Викитека", "type": "string", "deprecated": "Заполнятся автоматически из Викиданных" }, "Похоронен": { "description": "Место, где похоронен музыкант.", "type": "line" }, "from": { "type": "line" }, "nocat": { "type": "boolean", "autovalue": "1" } }, "format": "{{_\n| ________________ = _\n}}\n", "paramOrder": [ "Фон", "Имя", "Оригинал имени", "Изображение", "Ширина", "Описание изображения", "Имя при рождении", "Полное имя", "Дата рождения", "Место рождения", "Дата смерти", "Место смерти", "Похоронен", "Страна", "Профессии", "Годы активности", "Певческий голос", "Инструменты", "Жанры", "Псевдонимы", "Коллективы", "Лейбл текст", "Лейблы", "Награды", "Логотип", "Ширина логотипа", "Сайт", "Викисклад", "Викитека", "from", "nocat" ] } </templatedata> == См. также == * {{tl|Музыкальный коллектив}} * {{tl|Навигационная таблица музыкального исполнителя}} * {{cl|Шаблоны-карточки:Личности|1}} <includeonly> [[Категория:Шаблоны:Музыканты]] [[Категория:Шаблоны-карточки:Профессии культуры и искусства]] [[Категория:Шаблоны-карточки:Музыка]] </includeonly> 14ba03f3c4d9c6ee2c17a8274508fb62ce0dfa32 Шаблон:Пример с именами параметров 10 107 212 211 2025-01-25T21:00:41Z Vallenland 2 1 версия импортирована wikitext text/x-wiki <includeonly>{{#invoke:Parameter names example|main}}</includeonly><noinclude> {{Doc}} </noinclude> 2118cbf70aef4a440190a91ba85327a5cb8d3808 Модуль:Parameter names example 828 108 214 213 2025-01-25T21:00:42Z Vallenland 2 1 версия импортирована Scribunto text/plain -- This module implements {{parameter names example}}. local p = {} local function makeParam(s) local lb = '&#123;' local rb = '&#125;' return lb:rep(3) .. s .. rb:rep(3) end local function italicize(s) return "''" .. s .. "''" end local function plain(s) return s end function p._main(args, frame) -- Find how we want to format the arguments to the template. local formatFunc if args._display == 'italics' or args._display == 'italic' then formatFunc = italicize elseif args._display == 'plain' then formatFunc = plain else formatFunc = makeParam end -- Build the table of template arguments. local targs = {} for k, v in pairs(args) do if type(k) == 'number' then targs[v] = formatFunc(v) elseif not k:find('^_') then targs[k] = v end end -- Find the template name. local template if args._template then template = args._template else local currentTitle = mw.title.getCurrentTitle() if currentTitle.prefixedText:find('/sandbox$') or currentTitle.prefixedText:find('/песочница$') then template = currentTitle.prefixedText else template = currentTitle.basePageTitle.prefixedText end end -- Call the template with the arguments. frame = frame or mw.getCurrentFrame() local success, result = pcall( frame.expandTemplate, frame, {title = template, args = targs} ) if success then return result else return '' end end function p.main(frame) local args = require('Module:Arguments').getArgs(frame, { wrappers = 'Шаблон:Пример с именами параметров' }) return p._main(args, frame) end return p 64667ee447347f717db659027d7c4ec864230a93 Шаблон:Parameter names example 10 109 216 215 2025-01-25T21:00:42Z Vallenland 2 1 версия импортирована wikitext text/x-wiki #перенаправление [[Шаблон:Пример с именами параметров]] f42e4b1940da05c9e876c1c77cffa5c78e59c68d Шаблон:Легенда/styles.css 10 110 218 217 2025-01-25T21:00:42Z Vallenland 2 1 версия импортирована text text/plain /* Скопировано из [[:en:Template:Legend/styles.css]] с изменениями */ .ts-legend { page-break-inside: avoid; break-inside: avoid-column; display: block; font-size: 90%; } .thumb .ts-legend, figcaption .ts-legend { font-size: inherit; } .ts-legend-inline { display: inline-block; } .ts-legend-color { display: inline-block; min-width: 1.25em; height: 1.25em; line-height: 1.25; margin: 1px 0; text-align: center; border: 1px solid black; color: black; vertical-align: middle; } /*empty for now, but part of the design!*/ /*.ts-legend-text {}*/ /* [[Категория:Шаблоны:Подстраницы CSS]] */ 92f4aefe4d4206899f554e9262090e50a27a5171 Модуль:Message box/ombox.css 828 111 220 219 2025-01-25T21:00:42Z Vallenland 2 1 версия импортирована text text/plain /* Скопировано из [[:en:Module:Message box/ombox.css]] */ .ombox { margin: 4px 0; border-collapse: collapse; border: 1px solid var(--border-color-base, #a2a9b1); /* Default "notice" gray */ background-color: var(--background-color-neutral-subtle, #f8f9fa); box-sizing: border-box; } /* For the "small=yes" option. */ .ombox.mbox-small { font-size: 88%; line-height: 1.25em; } .ombox-speedy { border: 2px solid var(--border-color-error, #b32424); /* Red */ background-color: var(--background-color-error-subtle, #fee7e6); /* Pink */ } .ombox-delete { border: 2px solid var(--background-color-error--active, #b32424); /* Red */ } .ombox-content { border: 1px solid #f28500; /* Orange */ } .ombox-style { border: 1px solid #fc3; /* Yellow */ } .ombox-move { border: 1px solid #9932cc; /* Purple */ } .ombox-protection { border: 2px solid var(--border-color-base, #a2a9b1); /* Gray-gold */ } .ombox .mbox-text { border: none; /* @noflip */ padding: 0.25em 0.9em; width: 100%; } .ombox .mbox-image { border: none; /* @noflip */ padding: 2px 0 2px 0.9em; text-align: center; } .ombox .mbox-imageright { border: none; /* @noflip */ padding: 2px 0.9em 2px 0; text-align: center; } /* An empty narrow cell */ .ombox .mbox-empty-cell { border: none; padding: 0; width: 1px; } .ombox .mbox-invalid-type { text-align: center; } /* Хак, TODO: посмотреть, как оно на самом деле работает */ .ombox .mbox-textsmall-div { font-size: 90%; } @media (min-width: 720px) { .ombox { margin: 4px 10%; } .ombox.mbox-small { /* @noflip */ clear: right; /* @noflip */ float: right; /* @noflip */ margin: 4px 0 4px 1em; width: 238px; } /* Стили нотификаций для ноутбуков */ @media (max-width: 1366px) { .ombox { margin-left: 6%; margin-right: 6%; } } } /* [[Категория:Модули:Подстраницы CSS]] */ 6627874170f6674674bfa5796b2f7dfb6698cd81 Шаблон:Lua/Строка 10 112 222 221 2025-01-25T21:00:42Z Vallenland 2 1 версия импортирована wikitext text/x-wiki <includeonly>{{#if: {{{module|}}}{{{tech|}}} | <li>с использованием {{#if: {{{tech|}}} | {{{tech}}} | {{#if: {{{function|}}} | {{#if: {{{module|}}} | функции <code>{{#if: {{{line|}}} | [{{fullurl: Module:{{{module}}}|action=edit}}#mw-ce-l{{{line}}} {{{function}}}()] | [[{{{funcref|Module:{{{module}}}#{{{function}}}}}} | {{{function}}}()]]}}</code> из&#32;}}}}{{#if: {{{module|}}} | модуля [[Module:{{{module}}} | {{{module}}}]]}}}};}}</includeonly><noinclude>[[Категория:Шаблоны:Подстраницы шаблонов]]</noinclude> 5a35837338c2daee2d240a8e5335e8fec8e7d87e Модуль:Вложенные кавычки 828 113 224 223 2025-01-25T21:00:43Z Vallenland 2 1 версия импортирована Scribunto text/plain -- -- Re-implement [[Template:Вложенные кавычки]] in Lua -- Replaces «» to „“ without touching links -- require( 'strict' ) local getArgs local p = {} local function isEmpty( str ) return str == nil or str == '' end local function protectLinks( str ) local links, head = {}, 0 while true do local s, e, link = str:find( '(%[%[.-%]%])', head ) if not link then return str, links elseif link:find( '[[', 3, true ) then head = s + 2 else -- If the alt text contains '[', it can have one final ']'. if link:match( '^[^|]*|.-%[', 3 ) and str:sub( e + 1, e + 1 ) == ']' then link = link .. ']' end table.insert( links, link ) local placeholder = mw.ustring.char( 0xF0000 + #links ) str = str:gsub( link:gsub( '[$%%()*+%-.?[%]^]', '%%%0' ), placeholder ) head = str:find( placeholder ) + 1 end end end local function unprotectLinks( str, links ) for i, link in ipairs( links ) do str = str:gsub( mw.ustring.char( 0xF0000 + i ), link:gsub( '%%', '%%%%' ), 1 ) end return str end local function replace( str ) if isEmpty( str ) then return '' end str = mw.ustring.gsub( str, '«(.[^«»]-)»', '„%1“' ) return str end function p._main( text ) if isEmpty( text ) then return '' end local links = {} text, links = protectLinks( text ) if #links == 0 then return replace( text ) end -- Replace visible link text while keeping links intact for i, link in ipairs( links ) do local linkTarget = mw.text.trim( link, '%[%]' ) local linkText = '' local pipePos = link:find( '|', 1, true ) if pipePos ~= nil then local parts = mw.text.split( linkTarget, '|' ) linkTarget = parts[ 1 ] linkText = replace( parts[ 2 ] ) else linkText = replace( linkTarget ) end links[ i ] = string.format( '[[%s|%s]]', linkTarget, linkText ) end text = replace( text ) text = unprotectLinks( text, links ) return text end function p.main( frame ) getArgs = require( 'Module:Arguments' ).getArgs local args = getArgs( frame ) return p._main( args[ 1 ] ) end return p e7cf7cd583a5fa189c85ccf455feebd48aa60fa0 Шаблон:Инфобокс 10 114 225 2025-01-26T18:30:52Z Vallenland 2 Новая страница: «{| class="wikitable" style="float: right" | colspan="2" |Заголовок |- |Ячейка |Значение |- | colspan="2" |<nowiki>[[Foto1.png]]</nowiki> |} <nowiki> {| class="wikitable" style="float: right" | colspan="2" |Заголовок |- |Ячейка |Значение |- | colspan="2" |<nowiki>[[Foto1.png]]</nowiki> |} </nowiki>» wikitext text/x-wiki {| class="wikitable" style="float: right" | colspan="2" |Заголовок |- |Ячейка |Значение |- | colspan="2" |<nowiki>[[Foto1.png]]</nowiki> |} <nowiki> {| class="wikitable" style="float: right" | colspan="2" |Заголовок |- |Ячейка |Значение |- | colspan="2" |<nowiki>[[Foto1.png]]</nowiki> |} </nowiki> 448320f4fb2d0f654a4f9b671997e837b1666b45 226 225 2025-01-26T18:32:09Z Vallenland 2 wikitext text/x-wiki {| class="wikitable" style="float: right" | colspan="2" |Отсюда и поехали |} 5f1a9449dfb0c1ca6fde14db09617e9ab85fe1ce 227 226 2025-01-26T18:33:09Z Vallenland 2 wikitext text/x-wiki <nowiki>{| class="wikitable" style="float: right"</nowiki> | colspan="2" |Отсюда и поехали |} {| class="wikitable" style="float: right" | colspan="2" |Отсюда и поехали |} ЭТОТ ШАБЛОН ИСКЛЮЧИТЕЛЬНО ДЛЯ КОПИРОВАНИЯ КОДА ТАБЛИЦЫ И ПЕРЕДЕЛКИ ЕЁ В ВИЗУАЛЬНОМ РЕДАКТОРЕ! НЕ НУЖНО ЕГО ВСТАВЛЯТЬ НА СТРАНИЦУ! 1a542d10d6b3b1847fb9a2fc43492f4ff1444e62 Шаблон:Страна 10 115 228 2025-01-26T18:36:17Z Vallenland 2 Новая страница: «{| class="wikitable" style="float: right" | colspan="2" |Отсюда и поехали |}» wikitext text/x-wiki {| class="wikitable" style="float: right" | colspan="2" |Отсюда и поехали |} fb618423e55eaa49a357a6a24db2e78a0c42fba0 229 228 2025-01-26T20:05:24Z Vallenland 2 wikitext text/x-wiki {| class="wikitable" style="float: right" | colspan="2" |<center>'''{{{название}}}''' {{{другое_название}}} |- |<center>[[Файл:{{{флаг}}}.png|100px]] |<center>[[Файл:{{{герб}}}.png|100px]] |- | colspan="2" |<center>[[Файл:{{{фотография}}}|300px]] |- | colspan="2" |<center>{{{гимн}}} |- | colspan="2" |<center>{{{карта}}} |- |'''Язык(и)''' |{{{язык}}} |- |'''Столица''' |{{{столица}}} |- |'''Форма правления''' |{{{форма_правления}}} |- |'''Идеология''' |{{{идеология}}} |- |'''{{{глава}}}''' |{{{имя_главы}}} |- |'''Гос. религия''' |{{{религия}}} |- |'''Территория''' |{{{территория}}} |- |'''Население''' |{{{население}}} |- |'''Катойконимы''' |{{{названия_жителей}}} |- |'''Валюта''' |{{{валюта}}} |- |'''Домен''' |{{{домен}}} |} 4b0f423cd5aa00a894951640b19603b7d1d448aa 236 229 2025-01-26T21:50:48Z Vallenland 2 wikitext text/x-wiki {| class="wikitable" style="float: right" | colspan="2" |<center>'''<big>{{{название}}}</big>''' {{{другое_название}}} |- |<center>[[Файл:{{{флаг}}}.png|100px]] <nowiki>{{{описфлага}}}</nowiki> |<center>[[Файл:{{{герб}}}.png|100px]] <nowiki>{{{описгерба}}}</nowiki> |- | colspan="2" |<center>[[Файл:{{{фотография}}}|300px]] |- | colspan="2" |<center>{{{гимн}}} |- | colspan="2" |<center>{{{карта}}} |- |'''Язык(и)''' |{{{язык}}} |- |'''Столица''' |{{{столица}}} |- |'''Форма правления''' |{{{форма_правления}}} |- |'''Идеология''' |{{{идеология}}} |- |'''{{{глава}}}''' |{{{имя_главы}}} |- |'''Гос. религия''' |{{{религия}}} |- |'''Территория''' |{{{территория}}} |- |'''Население''' |{{{население}}} |- |'''Катойконимы''' |{{{названия_жителей}}} |- |'''Валюта''' |{{{валюта}}} |- |'''Домен''' |{{{домен}}} |} 858e3b60a8c7f4946d7015c94b5e0c460268e197 238 236 2025-01-26T21:52:41Z Vallenland 2 wikitext text/x-wiki {| class="wikitable" style="float: right" | colspan="2" |<center>'''<big>{{{название}}}</big>''' {{{другое_название}}} |- |<center>[[Файл:{{{флаг}}}.png|100px]] {{{описфлага}}} |<center>[[Файл:{{{герб}}}.png|100px]] {{{описгерба}}} |- | colspan="2" |<center>[[Файл:{{{фотография}}}|300px]] |- | colspan="2" |<center>{{{гимн}}} |- | colspan="2" |<center>{{{карта}}} |- |'''Язык(и)''' |{{{язык}}} |- |'''Столица''' |{{{столица}}} |- |'''Форма правления''' |{{{форма_правления}}} |- |'''Идеология''' |{{{идеология}}} |- |'''{{{глава}}}''' |{{{имя_главы}}} |- |'''Гос. религия''' |{{{религия}}} |- |'''Территория''' |{{{территория}}} |- |'''Население''' |{{{население}}} |- |'''Катойконимы''' |{{{названия_жителей}}} |- |'''Валюта''' |{{{валюта}}} |- |'''Домен''' |{{{домен}}} |} af50a2b64c791b0f9baeeef48e681c15cb091e1c Файл:Flag of Vallenland.png 6 116 230 2025-01-26T21:11:11Z Vallenland 2 wikitext text/x-wiki s a0f1490a20d0211c997b44bc357e1972deab8ae3 Файл:Центр Валленланда.png 6 117 231 2025-01-26T21:14:48Z Vallenland 2 wikitext text/x-wiki ы 5e6c96299a2f11e9b4f77ffc8c712ecd5da70df6 Файл:Sputnik map of Vallenland.png 6 118 232 2025-01-26T21:21:19Z Vallenland 2 wikitext text/x-wiki j 5c2dd944dde9e08881bef0894fe7b22a5c9c4b06 Валленланд 0 4 233 7 2025-01-26T21:23:16Z Vallenland 2 wikitext text/x-wiki {{Страна|название=Валленланд|другое_название=Валленландская севастократия|флаг=Flag of Vallenland|фотография=Центр Валленланда.png|гимн=[[Гимн Валленланда|"Крылатые качели"]]|язык=русский|столица=отсутствует|форма_правления=севастократия (королевство)|идеология=нелиберальная социал-демократия|глава=Севастократор|имя_главы=Макар Григорьев|религия=агностицизм|территория=4 060 кв.м|население=1 человек|названия_жителей=валленландцы, валленландец, валленляндка|валюта=рубль (планируется)|домен=.vl|карта=[[Файл:Sputnik map of Vallenland.png|300px]] Спутниковая карта Валленланда. Жёлтым выделена государственная граница севастократии.}} '''Валленланд''' (официально '''Валленландская Севастократия''', допускается также написание '''Валенланд''' и '''Валенландская Севастократия''') - микрогосударство на части зелёной территории города Пскова Псковской области. Официально [[Международное признание Валленланда|признан]] макрогосударствами как территория, принадлежащая Российской Федерации. Территории Валленланда расположены к востоку от 4-го многопрофильного лицея города Пскова. Они периодически контролируются то Валленлендом, то Россией. Площадь этих территорий, по измерениям Google Maps, составляет 4060 м<small><sup>2</sup></small> (0,406 га). Непостоянное [[Население Валленланда|население]] Валленланда составляет 1 человека, который и является правителем данного микрогосударства. По национальности он - цыган, следовательно, 100% населения Валленланда составляют цыгане. [[Мандат о независимости Валленланда|Мандатом о независимости]] от [[Национальный день принятия мандата о независимости Валленланда|22 января 2025 года]] установлены также полностью открытые границы и отсутствие государственного контроля за ними. В связи с этим через территорию Валленланда (чаще всего транзитом) проходят несколько десятков человек в день. Столица, равно как и административно-территориальное устройство, у Валленландской Севастократии отсутствует в связи со слишком маленькой площадью для необходимости этого. Из-за этого Валленланд можно отнести к сверхунитарным микрогосударствам. Валленланд имеет всего лишь одну общую границу с Российской Федерацией длиной в 453 м. Денежной единицы в силу временной нецелесообразности её введения (слишком малое число граждан) Валленланд не имеет. В противном случае денежной единицей станет российский рубль. Валленландская Севастократия долго находилась под властью многих государств - от Киевской Руси до Российской Федерации. Полный перечень всех стран, которые включали её в свой состав: Киевская Русь, Новгородская Республика, Псковская земля (позже - фактически под властью России), Русское государство, Российская империя, Эстония, Российская Советская Федеративная Социалистическая Республика, Великогерманский Рейх, вновь РСФСР и Российская Федерация. Независимый Валленланд появился 22 января 2025 года. Во главе Валленланда стоит [[Севастократор Валленланда|севастократор]] (до этого севастократором был высший придворный Византии, тем не менее, примерно соответствующий королю), имеющий абсолютную власть в стране до тех пор, пока не будет написана и принята первая [[конституция Валленланда]]. На 2025 год этот титул принадлежит [[Макар Григорьев|Макару Григорьеву]]. 60e947894cefc9d8765f0bbbe6cce97c8562bd6a 235 233 2025-01-26T21:49:02Z Vallenland 2 wikitext text/x-wiki {{Страна|название=Валленланд|другое_название=Валленландская севастократия|флаг=Flag of Vallenland|фотография=Центр Валленланда.png|гимн=[[Гимн Валленланда|"Крылатые качели"]]|язык=русский|столица=отсутствует|форма_правления=севастократия (королевство)|идеология=нелиберальная социал-демократия|глава=Севастократор|имя_главы=Макар Григорьев|религия=агностицизм|территория=4 060 кв.м|население=1 человек|названия_жителей=валленландцы, валленландец, валленляндка|валюта=рубль (планируется)|домен=.vl|карта=[[Файл:Sputnik map of Vallenland.png|300px]] Спутниковая карта Валленланда. Жёлтым выделена государственная граница севастократии.|герб=VVV}} '''Валленланд''' (официально '''Валленландская Севастократия''', допускается также написание '''Валенланд''' и '''Валенландская Севастократия''') - микрогосударство на части зелёной территории города Пскова Псковской области. Официально [[Международное признание Валленланда|признан]] макрогосударствами как территория, принадлежащая Российской Федерации. Территории Валленланда расположены к востоку от 4-го многопрофильного лицея города Пскова. Они периодически контролируются то Валленлендом, то Россией. Площадь этих территорий, по измерениям Google Maps, составляет 4060 м<small><sup>2</sup></small> (0,406 га). Непостоянное [[Население Валленланда|население]] Валленланда составляет 1 человека, который и является правителем данного микрогосударства. По национальности он - цыган, следовательно, 100% населения Валленланда составляют цыгане. [[Мандат о независимости Валленланда|Мандатом о независимости]] от [[Национальный день принятия мандата о независимости Валленланда|22 января 2025 года]] установлены также полностью открытые границы и отсутствие государственного контроля за ними. В связи с этим через территорию Валленланда (чаще всего транзитом) проходят несколько десятков человек в день. Столица, равно как и административно-территориальное устройство, у Валленландской Севастократии отсутствует в связи со слишком маленькой площадью для необходимости этого. Из-за этого Валленланд можно отнести к сверхунитарным микрогосударствам. Валленланд имеет всего лишь одну общую границу с Российской Федерацией длиной в 453 м. Денежной единицы в силу временной нецелесообразности её введения (слишком малое число граждан) Валленланд не имеет. В противном случае денежной единицей станет российский рубль. Валленландская Севастократия долго находилась под властью многих государств - от Киевской Руси до Российской Федерации. Полный перечень всех стран, которые включали её в свой состав: Киевская Русь, Новгородская Республика, Псковская земля (позже - фактически под властью России), Русское государство, Российская империя, Эстония, Российская Советская Федеративная Социалистическая Республика, Великогерманский Рейх, вновь РСФСР и Российская Федерация. Независимый Валленланд появился 22 января 2025 года. Во главе Валленланда стоит [[Севастократор Валленланда|севастократор]] (до этого севастократором был высший придворный Византии, тем не менее, примерно соответствующий королю), имеющий абсолютную власть в стране до тех пор, пока не будет написана и принята первая [[конституция Валленланда]]. На 2025 год этот титул принадлежит [[Макар Григорьев|Макару Григорьеву]]. 3051f9345e4a37f8b067c368dbcb5d08a3e1eaab 237 235 2025-01-26T21:52:12Z Vallenland 2 wikitext text/x-wiki {{Страна|название=Валленланд|другое_название=Валленландская севастократия|флаг=Flag of Vallenland|фотография=Центр Валленланда.png|гимн=[[Гимн Валленланда|"Крылатые качели"]]|язык=русский|столица=отсутствует|форма_правления=севастократия (королевство)|идеология=нелиберальная социал-демократия|глава=Севастократор|имя_главы=Макар Григорьев|религия=агностицизм|территория=4 060 кв.м|население=1 человек|названия_жителей=валленландцы, валленландец, валленляндка|валюта=рубль (планируется)|домен=.vl|карта=[[Файл:Sputnik map of Vallenland.png|300px]] Спутниковая карта Валленланда. Жёлтым выделена государственная граница севастократии.|герб=VVV|описфлага=Флаг Валленланда|описгерба=Национальная эмблема Валленланда}} '''Валленланд''' (официально '''Валленландская Севастократия''', допускается также написание '''Валенланд''' и '''Валенландская Севастократия''') - микрогосударство на части зелёной территории города Пскова Псковской области. Официально [[Международное признание Валленланда|признан]] макрогосударствами как территория, принадлежащая Российской Федерации. Территории Валленланда расположены к востоку от 4-го многопрофильного лицея города Пскова. Они периодически контролируются то Валленлендом, то Россией. Площадь этих территорий, по измерениям Google Maps, составляет 4060 м<small><sup>2</sup></small> (0,406 га). Непостоянное [[Население Валленланда|население]] Валленланда составляет 1 человека, который и является правителем данного микрогосударства. По национальности он - цыган, следовательно, 100% населения Валленланда составляют цыгане. [[Мандат о независимости Валленланда|Мандатом о независимости]] от [[Национальный день принятия мандата о независимости Валленланда|22 января 2025 года]] установлены также полностью открытые границы и отсутствие государственного контроля за ними. В связи с этим через территорию Валленланда (чаще всего транзитом) проходят несколько десятков человек в день. Столица, равно как и административно-территориальное устройство, у Валленландской Севастократии отсутствует в связи со слишком маленькой площадью для необходимости этого. Из-за этого Валленланд можно отнести к сверхунитарным микрогосударствам. Валленланд имеет всего лишь одну общую границу с Российской Федерацией длиной в 453 м. Денежной единицы в силу временной нецелесообразности её введения (слишком малое число граждан) Валленланд не имеет. В противном случае денежной единицей станет российский рубль. Валленландская Севастократия долго находилась под властью многих государств - от Киевской Руси до Российской Федерации. Полный перечень всех стран, которые включали её в свой состав: Киевская Русь, Новгородская Республика, Псковская земля (позже - фактически под властью России), Русское государство, Российская империя, Эстония, Российская Советская Федеративная Социалистическая Республика, Великогерманский Рейх, вновь РСФСР и Российская Федерация. Независимый Валленланд появился 22 января 2025 года. Во главе Валленланда стоит [[Севастократор Валленланда|севастократор]] (до этого севастократором был высший придворный Византии, тем не менее, примерно соответствующий королю), имеющий абсолютную власть в стране до тех пор, пока не будет написана и принята первая [[конституция Валленланда]]. На 2025 год этот титул принадлежит [[Макар Григорьев|Макару Григорьеву]]. 229a3d543083c03c941f37f0350e1e8b3612a6df 240 237 2025-01-26T22:09:45Z Vallenland 2 wikitext text/x-wiki {{Страна|название=Валленланд|другое_название=Валленландская севастократия|флаг=Flag of Vallenland|фотография=Центр Валленланда.png|гимн=[[Гимн Валленланда|"Крылатые качели"]]|язык=русский|столица=отсутствует|форма_правления=севастократия (королевство)|идеология=нелиберальная социал-демократия|глава=Севастократор|имя_главы=Макар Григорьев|религия=агностицизм|территория=4 060 кв.м|население=1 человек|названия_жителей=валленландцы, валленландец, валленляндка|валюта=рубль (планируется)|домен=.vl|карта=[[Файл:Sputnik map of Vallenland.png|300px]] Спутниковая карта Валленланда. Жёлтым выделена государственная граница севастократии.|герб=VVV|описфлага=Флаг Валленланда|описгерба=Национальная эмблема Валленланда}} '''Валленланд''' (официально '''Валленландская Севастократия''', допускается также написание '''Валенланд''' и '''Валенландская Севастократия''') - микрогосударство на части зелёной территории города Пскова Псковской области. Официально [[Международное признание Валленланда|признан]] макрогосударствами как территория, принадлежащая Российской Федерации. Территории Валленланда расположены к востоку от 4-го многопрофильного лицея города Пскова. Они периодически контролируются то Валленлендом, то Россией. Площадь этих территорий, по измерениям Google Maps, составляет 4060 м<small><sup>2</sup></small> (0,406 га). Непостоянное [[Население Валленланда|население]] Валленланда составляет 1 человека, который и является правителем данного микрогосударства. По национальности он - цыган, следовательно, 100% населения Валленланда составляют цыгане. [[Мандат о независимости Валленланда|Мандатом о независимости]] от [[Национальный день принятия мандата о независимости Валленланда|22 января 2025 года]] установлены также полностью открытые границы и отсутствие государственного контроля за ними. В связи с этим через территорию Валленланда (чаще всего транзитом) проходят несколько десятков человек в день. Столица, равно как и административно-территориальное устройство, у Валленландской Севастократии отсутствует в связи со слишком маленькой площадью для необходимости этого. Из-за этого Валленланд можно отнести к сверхунитарным микрогосударствам. Валленланд имеет всего лишь одну общую границу с Российской Федерацией длиной в 453 м. Денежной единицы в силу временной нецелесообразности её введения (слишком малое число граждан) Валленланд не имеет. В противном случае денежной единицей станет российский рубль. Валленландская севастократия долго находилась под властью многих государств - от Киевской Руси до Российской Федерации. Полный перечень всех стран, которые включали её в свой состав: Киевская Русь, Новгородская Республика, Псковская земля (позже - фактически под властью России), Русское государство, Российская империя, Эстония, Российская Советская Федеративная Социалистическая Республика, Великогерманский Рейх, вновь РСФСР и Российская Федерация. Независимый Валленланд появился 22 января 2025 года. Во главе Валленланда стоит [[Севастократор Валленланда|севастократор]] (до этого севастократором был высший придворный Византии, тем не менее, примерно соответствующий королю), имеющий абсолютную власть в стране до тех пор, пока не будет написана и принята первая [[конституция Валленланда]]. На 2025 год этот титул принадлежит [[Макар Григорьев|Макару Григорьеву]]. == Этимология == До создания микронации наименование "Валленланд" нигде особо не использовалось, за исключением виртуального государства в NationStates, которое не имеет никакого отношения к микронации Валленланд. Название для этой территории было установлено Мандатом о независимости, где сказано, что "отныне землю к западу от дома 26-го по улице Коммунальной до дороги к востоку от 4-м многопрофильного лицея, от дома 28-го по улице Коммунальной до тропы, ведущей к Рижскому проспекту, впредь именовать "Валленланд". Такое название было выбрано из-за того, что на немецком "wollen" означает "хотеть", а "land" - страна. Дословно другими словами - "страна, которую мы желаем". fb6c24043a566348786118bd8b5f62dbecf51c8c Файл:VVV.png 6 119 234 2025-01-26T21:48:34Z Vallenland 2 wikitext text/x-wiki vvv dbe6cae2f52b55095b513c15321b934146828d76 Заглавная страница 0 1 239 6 2025-01-26T21:54:26Z Vallenland 2 wikitext text/x-wiki __NOTOC__ <div style="border: solid black; background: rgb(100,100,100); background: radial-gradient(circle, rgba(127,201,255,1) 50%, rgba(82,127,63,1) 100%); color: white; text-align: center;">[[Файл:Vallenbox (greeting).png|центр|безрамки|160x160пкс]]<big>'''Добро пожаловать на Валленланд Вики, энциклопедию о микрогосударстве Валленланд.'''</big> Валленланд - микрогосударство на части территории города Пскова одноимённой области в России. Оно было основано в 2025 году и активно развивается. </div> <div style="border: solid black; background: rgb(100,100,100); background: radial-gradient(circle, rgba(127,201,255,1) 50%, rgba(82,127,63,1) 100%); color: white; text-align: center; flex: 1; margin: 2px; display: block;">'''Статьи, которые следует прочитать...''' [[Справка:Что такое Валленланд|Простым людям]]ㅤㅤ [[Справка:Как доказать гражданство для вики|Гражданам Валленланда]]ㅤㅤ [[Справка:Установка дипломатических отношений|Главам микронаций]] [[Справка:Как получить гражданство|Желающим получить гражданство Валленланда]]</div> <div style="border: solid black; background: rgb(100,100,100); background: radial-gradient(circle, rgba(127,201,255,1) 50%, rgba(82,127,63,1) 100%); color: white; text-align: center; flex: 1; margin: 2px; display: block;">'''Избранная статья''' '''Валленланд''' (официально '''Валленландская Севастократия''', допускается также написание '''Валенланд''' и '''Валенландская Севастократия''') - микрогосударство на части зелёной территории города Пскова Псковской области. Официально [[Международное признание Валленланда|признан]] макрогосударствами как территория, принадлежащая Российской Федерации. Территории Валленланда расположены к востоку от 4-го многопрофильного лицея города Пскова. Они периодически контролируются то Валленлендом, то Россией. Площадь этих территорий, по измерениям Google Maps, составляет 4060 м<small><sup>2</sup></small> (0,406 га). [[Валленланд|Читать далее...]] </div> 7ef86bcc2f6044e5862882a5b24da368d541833e 241 239 2025-01-26T22:10:12Z Vallenland 2 wikitext text/x-wiki __NOTOC__ <div style="border: solid black; background: rgb(100,100,100); background: radial-gradient(circle, rgba(127,201,255,1) 50%, rgba(82,127,63,1) 100%); color: white; text-align: center;">[[Файл:Vallenbox (greeting).png|центр|безрамки|160x160пкс]]<big>'''Добро пожаловать на Валленланд Вики, энциклопедию о микрогосударстве Валленланд.'''</big> Валленланд - микрогосударство на части территории города Пскова одноимённой области в России. Оно было основано в 2025 году и активно развивается. </div> <div style="border: solid black; background: rgb(100,100,100); background: radial-gradient(circle, rgba(127,201,255,1) 50%, rgba(82,127,63,1) 100%); color: white; text-align: center; flex: 1; margin: 2px; display: block;">'''Статьи, которые следует прочитать...''' [[Справка:Что такое Валленланд|Простым людям]]ㅤㅤ [[Справка:Как доказать гражданство для вики|Гражданам Валленланда]]ㅤㅤ [[Справка:Установка дипломатических отношений|Главам микронаций]] [[Справка:Как получить гражданство|Желающим получить гражданство Валленланда]]</div> <div style="border: solid black; background: rgb(100,100,100); background: radial-gradient(circle, rgba(127,201,255,1) 50%, rgba(82,127,63,1) 100%); color: white; text-align: center; flex: 1; margin: 2px; display: block;">'''Избранная статья''' '''Валленланд''' (официально '''Валленландская Севастократия''', допускается также написание '''Валенланд''' и '''Валенландская Севастократия''') - микрогосударство на части зелёной территории города Пскова Псковской области. Официально признан макрогосударствами как территория, принадлежащая Российской Федерации. Территории Валленланда расположены к востоку от 4-го многопрофильного лицея города Пскова. Они периодически контролируются то Валленлендом, то Россией. Площадь этих территорий, по измерениям Google Maps, составляет 4060 м<small><sup>2</sup></small> (0,406 га). [[Валленланд|Читать далее...]] </div> 3d3012a9cc8865fcf50f11a0d617711a0f5b4810